2008-12-28 25 views
15

Tôi muốn lấy điểm mã UCS-2 cho một chuỗi UTF-8 nhất định. Ví dụ: từ "hello" sẽ trở thành một cái gì đó như "0068 0065 006C 006C 006F". Xin lưu ý rằng các ký tự có thể là từ bất kỳ ngôn ngữ nào bao gồm các tập lệnh phức tạp như ngôn ngữ Đông Á.Làm cách nào để lấy số điểm mã cho một ký tự cụ thể trong chuỗi utf-8?

Vì vậy, sự cố xảy ra "chuyển đổi một ký tự đã cho đến mã mã UCS-2"

Nhưng làm cách nào? Xin vui lòng, bất kỳ loại trợ giúp sẽ rất rất nhiều đánh giá cao kể từ khi tôi vội vàng.

Cảm ơn trước


Transcription phản ứng hỏi của posted như một câu trả lời

Cảm ơn trả lời của bạn, nhưng nó cần phải được thực hiện trong PHP v 4 hoặc 5 nhưng không 6.

Chuỗi sẽ là đầu vào của người dùng, từ trường biểu mẫu.

Tôi muốn thực hiện một phiên bản PHP utf8to16 hoặc utf8decode như

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

bạn có thể giúp tôi với PHP hoặc nó có thể được thực hiện với PHP với phiên bản nêu trên?

Cảm ơn bạn một lần nữa.

+1

Những ngôn ngữ lập trình? –

Trả lời

7

Scott Reynen đã viết một hàm để convert UTF-8 into Unicode. Tôi thấy nó đang nhìn vào 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 
+13

Tôi đã viết hàm đó. Bản gốc ở đây, cùng với một số chức năng khác mà bạn có thể thấy hữu ích: http://randomchaos.com/documents/?source=php_and_unicode –

+1

@Reynen, Thế giới nhỏ, eh? Tôi đã chỉnh sửa bài đăng của tôi để cung cấp cho bạn tín dụng và một số quảng cáo. ; D – strager

+2

Xin vui lòng, xin vui lòng, gọi nó là 'utf8_to_utf16'. Cả hai đều là "Unicode" theo cách mà cả hai đều là biểu diễn cho các điểm mã Unicode. – DarkDust

11

Sử dụng tiện ích hiện có như iconv hoặc bất kỳ thư viện nào đi kèm với ngôn ngữ bạn đang sử dụng.

Nếu bạn nhấn mạnh vào việc tung giải pháp của riêng mình, hãy đọc ở định dạng UTF-8. Về cơ bản, mỗi điểm mã được lưu trữ là 1-4 byte, tùy thuộc vào giá trị của điểm mã. Các dãy như sau:

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

đâu mỗi x là một chút dữ liệu. Vì vậy, bạn có thể cho biết có bao nhiêu byte soạn mỗi điểm mã bằng cách xem byte đầu tiên: nếu nó bắt đầu bằng 0, đó là ký tự 1 byte. Nếu nó bắt đầu với 110, đó là một ký tự 2 byte. Nếu nó bắt đầu với 1110, đó là ký tự 3 byte. Nếu nó bắt đầu với 11110, đó là một ký tự 4 byte. Nếu nó bắt đầu bằng 10, đó là một byte không phải ban đầu của một ký tự nhiều byte. Nếu nó bắt đầu với 11111, đó là một ký tự không hợp lệ.

Khi bạn tìm ra số lượng byte trong ký tự, nó chỉ là vấn đề nếu bit twiddling. Cũng lưu ý rằng UCS-2 không thể đại diện cho các ký tự trên U + FFFF.

Vì bạn không nói rõ một ngôn ngữ, đây là một số mẫu mã C (kiểm tra lỗi bỏ qua):

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

Tôi thích thú vì tôi chỉ đưa ra vấn đề này để sinh viên về một kỳ thi chính thức.Dưới đây là một phác thảo của 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 

Và đây là một số mã 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

Rất tiếc, xin lỗi vì đã lãng phí thời gian của bạn với mã C. Nhưng tôi hy vọng bạn thấy sơ đồ nhỏ hữu ích. –

+0

Chức năng kiểm tra() có bị hỏng không? Không nên thử nghiệm: if ((c & 0xC0)! = 0x80)? Ngoài ra, macro RAISE là gì? –

+1

Cảm ơn bạn đã sửa lỗi trong hàm check(). Phục vụ tôi đúng khi viết mã vào đêm trước trận chung kết. RAISE là từ http://www.cs.princeton.edu/software/cii/. –

4

mã PHP (mà giả định hợp lệ utf-8, không có kiểm tra cho utf-8 không hợp lệ):

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); 
    } 
+0

Rất đẹp, ngoại trừ việc nó không thành công khi nhân vật đã là ASCII. 0x10 phải là 0x80, để nắm bắt phạm vi ASCII đầy đủ. – TextGeek

Các vấn đề liên quan