Znak Unicode w łańcuchu PHP

To pytanie wygląda żenująco prosto, ale nie udało mi się znaleźć odpowiedzi.

Jaki jest odpowiednik PHP dla następującej linii kodu C#?

string str = "\u1000";

Ta próbka tworzy ciąg znaków z pojedynczym znakiem Unicode, którego "wartość liczbowa Unicode" wynosi 1000 w układzie szesnastkowym (4096 w układzie dziesiętnym).

Czyli w PHP Jak mogę utworzyć ciąg znaków z pojedynczym znakiem Unicode, którego" wartość liczbowa Unicode " jest znana?

 123
Author: Blackhole, 2011-05-19

7 answers

Ponieważ JSON bezpośrednio wspiera składnię \uxxxx pierwsze co przychodzi mi do głowy to:

$unicodeChar = '\u1000';
echo json_decode('"'.$unicodeChar.'"');

Inną opcją byłoby użycie mb_convert_encoding()

echo mb_convert_encoding('က', 'UTF-8', 'HTML-ENTITIES');

Lub użyć bezpośredniego mapowania pomiędzy UTF-16be (big endian) a kodem Unicode:

echo mb_convert_encoding("\x10\x00", 'UTF-8', 'UTF-16BE');
 151
Author: Stefan Gehrig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-19 12:48:53

PHP 7.0.0 wprowadził składnię "Unicode codepoint escape" .

Możliwe jest teraz łatwe zapisywanie znaków Unicode za pomocą podwójnie cytowanego lub heredoc, bez wywoływania żadnej funkcji.

$unicodeChar = "\u{1000}";
 83
Author: Blackhole,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-09 23:49:27

PHP nie zna tych sekwencji escape Unicode. Ale ponieważ nieznane sekwencje escape pozostają nienaruszone, możesz napisać własną funkcję, która konwertuje takie sekwencje escape Unicode:

function unicodeString($str, $encoding=null) {
    if (is_null($encoding)) $encoding = ini_get('mbstring.internal_encoding');
    return preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/u', create_function('$match', 'return mb_convert_encoding(pack("H*", $match[1]), '.var_export($encoding, true).', "UTF-16BE");'), $str);
}

Lub z anonimowym wyrażeniem funkcji zamiast create_function:

function unicodeString($str, $encoding=null) {
    if (is_null($encoding)) $encoding = ini_get('mbstring.internal_encoding');
    return preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/u', function($match) use ($encoding) {
        return mb_convert_encoding(pack('H*', $match[1]), $encoding, 'UTF-16BE');
    }, $str);
}

Jego użycie:

$str = unicodeString("\u1000");
 18
Author: Gumbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-19 12:59:29

Zastanawiam się, dlaczego nikt jeszcze o tym nie wspomniał, ale możesz zrobić prawie równoważną wersję używając sekwencji escape w podwójnych cytowanych ciągach :

\x[0-9A-Fa-f]{1,2}

Sekwencja znaków pasujących do wyrażenia regularnego jest znak w notacji szesnastkowej.

Przykład ASCII:

<?php
    echo("\x48\x65\x6C\x6C\x6F\x20\x57\x6F\x72\x6C\x64\x21");
?>

Hello World!

Więc dla twojej sprawy, wszystko, co musisz zrobić, to $str = "\x30\xA2";. Ale to są bajty , a nie znaki. Bajt reprezentacja kodu Unicode pokrywa się z UTF-16 big endian, więc możemy ją wydrukować bezpośrednio jako taką:
<?php
    header('content-type:text/html;charset=utf-16be');
    echo("\x30\xA2");
?>

Jeśli używasz innego kodowania, musisz odpowiednio zmienić bajty (głównie robione za pomocą biblioteki, choć możliwe również ręcznie).

UTF-16 mały endian przykład:

<?php
    header('content-type:text/html;charset=utf-16le');
    echo("\xA2\x30");
?>

Przykład UTF-8:

<?php
    header('content-type:text/html;charset=utf-8');
    echo("\xE3\x82\xA2");
?>

Istnieje również pack funkcja, ale można oczekiwać, że będzie powolny.

 17
Author: Pacerier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-27 17:05:39

Try Portable UTF-8:

$str = utf8_chr( 0x1000 );
$str = utf8_chr( '\u1000' );
$str = utf8_chr( 4096 );
Wszystkie działają dokładnie tak samo. Znak kodowy można uzyskać za pomocą utf8_ord(). Przeczytaj więcej o Portable UTF-8.
 7
Author: Hamid Sarfraz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-03 19:49:17
html_entity_decode('&#x30a8;', 0, 'UTF-8');
To też działa. Jednak rozwiązanie json_decode() jest o wiele szybsze(około 50 razy).
 6
Author: flori,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-18 10:30:46

Jak wspomnieli inni, PHP 7 wprowadza obsługę składni \u Unicode bezpośrednio.

Jak wspomniano również przez innych, jedynym sposobem na uzyskanie wartości łańcuchowej z dowolnego sensownego opisu znaków Unicode w PHP jest konwersja z czegoś innego (np. parsowanie JSON, parsowanie HTML lub inna forma). Ale wiąże się to z kosztami wydajności w czasie eksploatacji.

Jest jednak jeszcze jedna opcja. Znak można zakodować bezpośrednio w PHP za pomocą binarnych znaków specjalnych \x. Na \x składnia escape jest również obsługiwana w PHP 5.

Jest to szczególnie przydatne, jeśli wolisz nie wprowadzać znaku bezpośrednio w łańcuchu poprzez jego naturalną formę. Na przykład, jeśli jest to niewidoczny znak kontrolny lub inny trudny do wykrycia biały znak.

Po pierwsze, przykład dowodu:

// Unicode Character 'HAIR SPACE' (U+200A)
$htmlEntityChar = "&#8202;";
$realChar = html_entity_decode($htmlEntityChar);
$phpChar = "\xE2\x80\x8A";
echo 'Proof: ';
var_dump($realChar === $phpChar); // bool(true)

Zauważ, że, jak wspomniał Pacerier w innej odpowiedzi, ten kod binarny jest unikalny dla określonego kodowania znaków. W powyższym przykładzie \xE2\x80\x8A jest kodowaniem binarnym dla U + 200A w UTF-8.

Następne pytanie brzmi, jak przejść z U+200A do \xE2\x80\x8A?

Poniżej znajduje się skrypt PHP do generowania sekwencji escape dla dowolnego znaku, opartego na łańcuchu JSON, encji HTML lub dowolnej innej metodzie, gdy masz go jako natywny ciąg znaków.

function str_encode_utf8binary($str) {
    /** @author Krinkle 2018 */
    $output = '';
    foreach (str_split($str) as $octet) {
        $ordInt = ord($octet);
        // Convert from int (base 10) to hex (base 16), for PHP \x syntax
        $ordHex = base_convert($ordInt, 10, 16);
        $output .= '\x' . $ordHex;
    }
    return $output;
}

function str_convert_html_to_utf8binary($str) {
    return str_encode_utf8binary(html_entity_decode($str));
}
function str_convert_json_to_utf8binary($str) {
    return str_encode_utf8binary(json_decode($str));
}

// Example for raw string: Unicode Character 'INFINITY' (U+221E)
echo str_encode_utf8binary('∞') . "\n";
// \xe2\x88\x9e

// Example for HTML: Unicode Character 'HAIR SPACE' (U+200A)
echo str_convert_html_to_utf8binary('&#8202;') . "\n";
// \xe2\x80\x8a

// Example for JSON: Unicode Character 'HAIR SPACE' (U+200A)
echo str_convert_json_to_utf8binary('"\u200a"') . "\n";
// \xe2\x80\x8a
 1
Author: Krinkle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-18 19:58:27