2010-05-01 32 views
4

有很多方法可以代表+1百萬UTF-8 characters。用macron拉丁首字母「A」(Ā)。這是unicode代碼點U+0100,十六進制數0xc4 0x80,十進制數196 128和二進制11000100 10000000你將如何創建一個所有UTF-8字符的字符串?

我想創建一個用於測試應用程序的前65,535個UTF-8字符的集合。這些都是代碼點爲U+FFFF(byte3)的所有unicode字符。

是否有可能執行類似for($x=0)循環的操作,然後將生成的小數轉換爲另一個基(如十六進制),從而允許創建匹配的unicode字符?然而

$char = "\xc4\x80"; 
// or 
$char = chr(196).chr(128); 

,我不知道如何把它變成一個自動的過程:

我可以使用像這樣創造的價值Ā

// fail! 
$char = "\x". dechex($a). "\x". dexhex($b); 
+0

'U + FFFF'不是根據定義的Unicode字符(既不是U + FFFE也不是用作字節順序標記)。 – 2010-05-01 05:09:45

+1

您的問題讓代碼點(數字)與編碼(字節序列)相混淆。更確切的說法是。 「這是unicode代碼點U + 0100(十進制:256),它的UTF-8編碼是兩個字節:0xc4 0x80(或十進制196,128)...」 – leonbloy 2010-05-01 12:29:47

+0

感謝您糾正我 – Xeoncross 2010-05-01 16:34:51

回答

5

您可以利用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」。)

+1

+1賓果。我猜這是最好的方法。你取每個碼點(整數),把它打包成32位LE(相當於在UCS-4LE中手動「編碼」它),並要求iconv將編碼轉換爲UTF-8。 (我已經說過PHP在Unicode上很爛?) – leonbloy 2010-05-01 12:34:42

+0

我不確定。我可以說「PHP在Unicode上很糟糕」,以防萬一你沒有,如果有幫助的話。 – bobince 2010-05-01 13:43:36

+1

太棒了!我現在有一個有用的UTF-8字符列表,可以通過正則表達式測試運行。 – Xeoncross 2010-05-01 16:41:33

0

:) 當然最後一個不會工作。 \ x序列屬於雙引號字符串。

$char = chr(196).chr(128);有什麼問題?與chr($ a).chr($ b)我的意思是。

4

我不確定你是否可以通過編程的方式來完成這項工作,主要是因爲Unicode代碼點和字符之間存在差異。查看http://www.unicode.org/standard/where瞭解由代碼點組合所代表的字符的幾個示例。

一些代碼點本身沒有意義,只能與另一個字符(認爲重音)結合使用。有關代碼點的列表,請參閱http://www.unicode.org/charts/charindex.html,並查看包含所有「組合」代碼點的部分。

另外,爲了在測試應用程序中使用,除了可能的UTF-8代碼點列表外,還需要其他東西,即應用程序需要能夠正常恢復的幾個無效/格式錯誤的UTF-8序列。

爲此,請查看Markus Kuhn's Unicode stress test

1

我快譯這從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,並且還有其他幾個缺口來組合字符和保留字符。

0
<?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… 
相關問題