2008-12-28 34 views
15

我想獲得給定的UTF-8字符串的UCS-2碼點。例如,「你好」這個詞應該變成「0068 0065 006C 006C 006F」。請注意,角色可能來自任何語言,包括東亞語言等複雜腳本。如何獲取utf-8字符串中給定字符的代碼點號?

那麼,問題歸結爲「給定字符轉換爲其UCS-2代碼點」

怎麼會呢?因爲我非常匆忙,請任何形式的幫助都會非常感激。

在此先感謝


提問的迴應轉錄張貼作爲一個答案

感謝您的答覆,但它需要在PHP 4節或5做,但不是6

該字符串將是來自表單字段的用戶輸入。

我想要實現的一個utf8to16 PHP版本或utf8decode像

function get_ucs2_codepoint($char) 
{ 
    // calculation of ucs2 codepoint value and assign it to $hex_codepoint 
    return $hex_codepoint; 
} 

你能幫我用PHP或者可以將它與PHP版本與上述做些什麼呢?

再次感謝您。

+1

哪種編程語言? – 2008-12-28 04:57:29

回答

7

Scott Reynen寫了一個函數來convert UTF-8 into Unicode。我發現它看着PHP documentation

function utf8_to_unicode($str) { 

    $unicode = array();   
    $values = array(); 
    $lookingFor = 1; 

    for ($i = 0; $i < strlen($str); $i++) { 
     $thisValue = ord($str[ $i ]); 
    if ($thisValue < ord('A')) { 
     // exclude 0-9 
     if ($thisValue >= ord('0') && $thisValue <= ord('9')) { 
      // number 
      $unicode[] = chr($thisValue); 
     } 
     else { 
      $unicode[] = '%'.dechex($thisValue); 
     } 
    } else { 
      if ($thisValue < 128) 
     $unicode[] = $str[ $i ]; 
      else { 
       if (count($values) == 0) $lookingFor = ($thisValue < 224) ? 2 : 3;     
       $values[] = $thisValue;     
       if (count($values) == $lookingFor) { 
        $number = ($lookingFor == 3) ? 
         (($values[0] % 16) * 4096) + (($values[1] % 64) * 64) + ($values[2] % 64): 
         (($values[0] % 32) * 64) + ($values[1] % 64); 
      $number = dechex($number); 
      $unicode[] = (strlen($number)==3)?"%u0".$number:"%u".$number; 
        $values = array(); 
        $lookingFor = 1; 
      } // if 
     } // if 
    } 
    } // for 
    return implode("",$unicode); 

} // utf8_to_unicode 
11

使用現有的實用程序,例如iconv或任何隨您所用語言提供的庫。

如果你堅持自己的解決方案,請閱讀UTF-8格式。基本上,每個代碼點存儲爲1-4個字節,具體取決於代碼點的值。的範圍如下:

  • U + 0000 - U + 007F:1字節:0xxxxxxx
  • U + 0080 - U + 07FF:2個字節:110xxxxx 10xxxxxx
  • U + 0800 - U + FFFF :3個字節:1110xxxx 10xxxxxx 10xxxxxx
  • U + 10000 - U + 10FFFF:4個字節:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

其中各X是一個數據位。因此,通過查看第一個字節,可以知道每個代碼點有多少個字節組成:如果以0開頭,則是1個字節的字符。如果它以110開頭,它是一個2字節的字符。如果它以1110開始,它是一個3字節的字符。如果它以11110開始,它是一個4字節的字符。如果它以10開頭,則它是多字節字符的非首字節。如果它以11111開始,它是一個無效的字符。

一旦你找出字符中有多少字節,這只是一個問題,如果有點扭曲。另請注意,UCS-2無法表示U + FFFF以上的字符。

既然你沒有指定語言,這裏是一些示例C代碼(檢查省略錯誤):

wchar_t utf8_char_to_ucs2(const unsigned char *utf8) 
{ 
    if(!(utf8[0] & 0x80))  // 0xxxxxxx 
    return (wchar_t)utf8[0]; 
    else if((utf8[0] & 0xE0) == 0xC0) // 110xxxxx 
    return (wchar_t)(((utf8[0] & 0x1F) << 6) | (utf8[1] & 0x3F)); 
    else if((utf8[0] & 0xF0) == 0xE0) // 1110xxxx 
    return (wchar_t)(((utf8[0] & 0x0F) << 12) | ((utf8[1] & 0x3F) << 6) | (utf8[2] & 0x3F)); 
    else 
    return ERROR; // uh-oh, UCS-2 can't handle code points this high 
} 
4

我覺得好笑,因爲我只是給這個問題以學生期末考試。下面是UTF-8的草圖:

hex   binary     UTF-8 binary 
0000-007F 00000000 0abcdefg => 0abcdefg 
0080-07FF 00000abc defghijk => 110abcde 10fghijk 
0800-FFFF abcdefgh ijklmnop => 1110abcd 10efghij 10klmnop 

而且這裏的一些代碼C99:

static void check(char c) { 
    if ((c & 0xc0) != 0xc0) RAISE(Bad_UTF8); 
} 

uint16_t Utf8_decode(char **p) { // return code point and advance *p 
    char *s = *p; 
    if ((s[0] & 0x80) == 0) { 
    (*p)++; 
    return s[0]; 
    } else if ((s[0] & 0x40) == 0) { 
    RAISE (Bad_UTF8); 
    return ~0; // prevent compiler warning 
    } else if ((s[0] & 0x20) == 0) { 
    if ((s[0] & 0xf0) != 0xe0) RAISE (Bad_UTF8); 
    check(s[1]); check(s[2]); 
    (*p) += 3; 
    return ((s[0] & 0x0f) << 12) 
     + ((s[1] & 0x3f) << 6) 
     + ((s[2] & 0x3f)); 
    } else { 
    check(s[1]); 
    (*p) += 2; 
    return ((s[0] & 0x1f) << 6) 
     + ((s[1] & 0x3f)); 
    } 
}  
+0

哎呀,對不起,浪費你的時間與C代碼。但我希望你找到有用的小圖。 – 2008-12-28 07:15:37

+0

是不是check()函數被破壞?不應該測試:if((c&0xC0)!= 0x80)?另外,什麼是RAISE宏? – 2008-12-28 08:02:35

+1

感謝check()函數中的錯誤修復。在決賽前的晚上爲我編寫代碼是正確的。 RAISE來自http://www.cs.princeton.edu/software/cii/。 – 2008-12-29 02:03:15

4

PHP代碼(假定有效UTF-8,無校驗非有效UTF-8):

function ord_utf8($c) { 
    $b0 = ord($c[0]); 
    if ($b0 < 0x10) { 
     return $b0; 
     } 
    $b1 = ord($c[1]); 
    if ($b0 < 0xE0) { 
     return (($b0 & 0x1F) << 6) + ($b1 & 0x3F); 
     } 
    return (($b0 & 0x0F) << 12) + (($b1 & 0x3F) << 6) + (ord($c[2]) & 0x3F); 
    }