Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get code point number for a given character in a utf-8 string?

Tags:

php

unicode

I want to get the UCS-2 code points for a given UTF-8 string. For example the word "hello" should become something like "0068 0065 006C 006C 006F". Please note that the characters could be from any language including complex scripts like the east asian languages.

So, the problem comes down to "convert a given character to its UCS-2 code point"

But how? Please, any kind of help will be very very much appreciated since I am in a great hurry.


Transcription of questioner's response posted as an answer

Thanks for your reply, but it needs to be done in PHP v 4 or 5 but not 6.

The string will be a user input, from a form field.

I want to implement a PHP version of utf8to16 or utf8decode like

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

Can you help me with PHP or can it be done with PHP with version mentioned above?

like image 657
anjan Avatar asked Dec 28 '08 04:12

anjan


People also ask

What is code point in UTF-8?

Code points allow abstraction from the term character and are the atomic unit of storage of information in an encoding. Most code points represent a single character, but some represent information such as formatting. UTF-8 is a “variable-width” encoding standard.

How do I find the Unicode value of a character in python?

In Python, the built-in functions chr() and ord() are used to convert between Unicode code points and characters. A character can also be represented by writing a hexadecimal Unicode code point with \x , \u , or \U in a string literal.

What is code point in character?

A code point is a number assigned to represent an abstract character in a system for representing text (such as Unicode). In Unicode, a code point is expressed in the form "U+1234" where "1234" is the assigned number. For example, the character "A" is assigned a code point of U+0041.


2 Answers

Use an existing utility such as iconv, or whatever libraries come with the language you're using.

If you insist on rolling your own solution, read up on the UTF-8 format. Basically, each code point is stored as 1-4 bytes, depending on the value of the code point. The ranges are as follows:

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

Where each x is a data bit. Thus, you can tell how many bytes compose each code point by looking at the first byte: if it begins with a 0, it's a 1-byte character. If it begins with 110, it's a 2-byte character. If it begins with 1110, it's a 3-byte character. If it begins with 11110, it's a 4-byte character. If it begins with 10, it's a non-initial byte of a multibyte character. If it begins with 11111, it's an invalid character.

Once you figure out how many bytes are in the character, it's just a matter if bit twiddling. Also note that UCS-2 cannot represent characters above U+FFFF.

Since you didn't specify a language, here's some sample C code (error checking omitted):

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
}
like image 78
Adam Rosenfield Avatar answered Sep 24 '22 00:09

Adam Rosenfield


Scott Reynen wrote a function to convert UTF-8 into Unicode. I found it looking at the 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
like image 34
strager Avatar answered Sep 25 '22 00:09

strager