Существует много способов представить +1 миллион символов UTF-8 . Возьмите латинскую столицу «А» с макроном ( Ā
). Это юникодная кодовая точка U+0100
, шестнадцатеричный номер 0xc4 0x80
, десятичное число 196 128
и двоичный код 11000100 10000000
.
Я хотел бы создать коллекцию из первых 65535 символов UTF-8 для использования в тестовых приложениях. Это все символы Unicode до кодовой точки U+FFFF
(byte3).
Можно ли сделать что-то вроде цикла for($x=0)
а затем преобразовать полученный десятичный код в другую базу (например, hex), которая позволила бы создать соответствующий символ юникода?
Я могу создать значение Ā
используя что-то вроде этого:
$char = "\xc4\x80"; // or $char = chr(196).chr(128);
Однако я не уверен, как превратить это в автоматизированный процесс.
// fail! $char = "\x". dechex($a). "\x". dexhex($b);
Вы можете использовать iconv
(или несколько других функций) для преобразования номера кодовой точки в строку UTF-8:
function unichr($i) { return iconv('UCS-4LE', 'UTF-8', pack('V', $i)); } $codeunits = array(); for ($i = 0; $i<0xD800; $i++) $codeunits[] = unichr($i); for ($i = 0xE000; $i<0xFFFF; $i++) $codeunits[] = unichr($i); $all = implode($codeunits);
(Я избегал суррогатного диапазона 0xD800-0xDFFF, так как они недействительны для ввода самих UTF-8, это будет «CESU-8».)
Я не уверен, что вы можете сделать это программно, главным образом потому, что есть разница между кодовой точкой Unicode и символом. См. http://www.unicode.org/standard/where для нескольких примеров символов, которые представлены комбинацией кодовых точек.
Некоторые кодовые точки не имеют смысла сами по себе и могут использоваться только в сочетании с другим персонажем (думаю, акценты). См. http://www.unicode.org/charts/charindex.html список кодовых точек и посмотрите раздел со всеми «комбинирующими» кодовыми точками.
Кроме того, для использования в тестовых приложениях вам потребуется что-то еще, кроме списка возможных кодовых точек UTF-8, а именно несколько недействительных / некорректных последовательностей UTF-8, которые ваше приложение должно будет изящно восстановить.
Для этого взгляните на стресс-тест Юникода Маркуса Куна .
Я быстро перевел это с C, но он должен дать вам идею:
function encodeUTF8( $inValue ) { $result = ""; if ( $inValue < 0x00000080 ) { $result .= chr( $inValue ); $extra = 0; } else if ( $inValue < 0x00000800 ) { $result .= chr( 0x00C0 | ( ( $inValue >> 6 ) & 0x001F ) ); $extra = 6; } else if ( $inValue < 0x00010000 ) { $result .= chr( 0x00E0 | ( ( $inValue >> 12 ) & 0x000F ) ); $extra = 12; } else if ( $inValue < 0x00200000 ) { $result .= chr( 0x00F0 | ( ( $inValue >> 18 ) & 0x0007 ) ); $extra = 18; } else if ( $inValue < 0x04000000 ) { $result .= chr( 0x00F8 | ( ( $inValue >> 24 ) & 0x0003 ) ); $extra = 24; } else if ( $inValue < 0x80000000 ) { $result .= chr( 0x00FC | ( ( $inValue >> 30 ) & 0x0001 ) ); $extra = 30; } while ( $extra > 0 ) { $result .= chr( 0x0080 | ( ( $inValue >> ( $extra -= 6 ) ) & 0x003F ) ); } return $result; }
Логика звучит, но я не уверен в php, поэтому обязательно проверьте ее. Я никогда не пытался использовать chr
как это.
Есть много значений, которые вы бы не хотели кодировать, например 0xD000-0xDFFF, 0xE000-0xF8FF и 0xFFF0-0xFFFF, и есть несколько других пробелов для объединения символов и зарезервированных символов.
🙂 Конечно, последний не сработает. Последовательность \ x принадлежит строкам с двойными кавычками.
что не так с $char = chr(196).chr(128);
? с chr ($ a) .chr ($ b) Я имею в виду.
<?php function chr_utf8($n,$f='C*'){ return $n<(1<<7)?chr($n):($n<1<<11?pack($f,192|$n>>6,1<<7|191&$n): ($n<(1<<16)?pack($f,224|$n>>12,1<<7|63&$n>>6,1<<7|63&$n): ($n<(1<<20|1<<16)?pack($f,240|$n>>18,1<<7|63&$n>>12,1<<7|63&$n>>6,1<<7|63&$n):''))); } echo implode('',array_map('chr_utf8',range(0,65535))); // Output a big string, you can increase the range to 1114111…