Как получить номер кодовой точки для данного символа в строке utf-8?

Я хочу получить кодовые точки UCS-2 для данной строки UTF-8. Например, слово «привет» должно выглядеть как «0068 0065 006C 006C 006F». Обратите внимание, что символы могут быть из любого языка, включая сложные шрифты, такие как восточноазиатские языки.

Итак, проблема сводится к «преобразованию данного символа в его кодовую точку UCS-2».

Но как? Мы будем очень благодарны за любую помощь, так как я очень тороплюсь.


Транскрипция ответа спрашивающего, отправленного в качестве ответа

Спасибо за ответ, но это нужно делать в PHP версии 4 или 5, но не в версии 6.

Строка будет вводиться пользователем из поля формы.

Я хочу реализовать PHP-версию utf8to16 или utf8decode, например

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

Можете ли вы помочь мне с PHP или это можно сделать с помощью PHP с версией, указанной выше?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
19
0
17 809
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Используйте существующую утилиту, такую ​​как 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
}

Меня позабавило, потому что я только что дал эту задачу студентам на выпускном экзамене. Вот набросок 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));
  }
}    

Упс, извините за потраченное время на код C. Но я надеюсь, что эта маленькая диаграмма окажется для вас полезной.

Norman Ramsey 28.12.2008 10:15

Не нарушена ли функция check ()? Разве это не должно быть тестирование: if ((c & 0xC0)! = 0x80)? Кроме того, что такое макрос RAISE?

Jonathan Leffler 28.12.2008 11:02

Спасибо за исправление ошибки в функции check (). Так мне подходит для написания кода в ночь перед финалом. RAISE от cs.princeton.edu/software/cii.

Norman Ramsey 29.12.2008 05:03
Ответ принят как подходящий

Скотт Рейнен записал функцию в конвертировать UTF-8 в Unicode. Я нашел это, глядя на Документация PHP.

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

Я написал эту функцию. Оригинал находится здесь вместе с некоторыми другими функциями, которые могут оказаться полезными: randomchaos.com/documents/?source=php_and_unicode

Scott Reynen 28.12.2008 19:47

@Reynen, Маленький мир, а? Я отредактировал свой пост, чтобы отдать должное и немного рекламы. ; D

strager 28.12.2008 23:56

Пожалуйста, назовите его utf8_to_utf16. Оба являются «Unicode» в том смысле, что оба являются представлениями кодовых точек Unicode.

DarkDust 10.05.2015 10:05

@ScottReynen 404 ссылка, у вас все еще есть оригинал?

CPHPython 08.10.2018 16:43

Код 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);
    }

Очень хорошо, за исключением того, что он не работает, когда символ уже является ASCII. 0x10 должно быть 0x80, чтобы поймать полный диапазон ASCII.

TextGeek 30.08.2017 19:01

Используйте mb_ord() в php >= 7.2.

Или эта функция:

function ord_utf8($c) {
    $len = strlen($c);
    $code = ord($c);
    if ($len > 1) {
        $code &= 0x7F >> $len;
        for($i = 1; $i < $len; $i++) {
            $code <<= 6;
            $code += ord($c[$i]) & 0x3F;
        }
    }
    return $code;
}

$c - это персонаж. Если вам нужно преобразовать строку в массив символов, вы можете использовать это.

$string = 'abcde';
$string = preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY);

Другие вопросы по теме