Как бы вы создали строку из всех символов UTF-8?

Существует много способов представить +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…