Мне нужно иметь возможность использовать ord () для получения того же значения, что и функция charCodeAt () javascript. Проблема в том, что ord () не поддерживает UTF8.
Как я могу заставить Ą перевести на 260 в PHP? Я пробовал некоторые функции uniord там, но все они сообщают 256 вместо 260.
Большое спасибо за любую помощь!
С уважением
ord()
работает байт за байт (как и большинство стандартных строковых функций PHP, если не все). Вам нужно будет преобразовать его самостоятельно, например, с помощью расширения многобайтовой строки:
$utf8Character = 'Ą'; list(, $ord) = unpack('N', mb_convert_encoding($utf8Character, 'UCS-4BE', 'UTF-8')); echo $ord; # 260
Версия mbstring:
function utf8_char_code_at($str, $index) { $char = mb_substr($str, $index, 1, 'UTF-8'); if (mb_check_encoding($char, 'UTF-8')) { $ret = mb_convert_encoding($char, 'UTF-32BE', 'UTF-8'); return hexdec(bin2hex($ret)); } else { return null; } }
используя htmlspecialchars и htmlspecialchars_decode для получения одного символа:
function utf8_char_code_at($str, $index) { $char = ''; $str_index = 0; $str = utf8_scrub($str); $len = strlen($str); for ($i = 0; $i < $len; $i += 1) { $char .= $str[$i]; if (utf8_check_encoding($char)) { if ($str_index === $index) { return utf8_ord($char); } $char = ''; $str_index += 1; } } return null; } function utf8_scrub($str) { return htmlspecialchars_decode(htmlspecialchars($str, ENT_SUBSTITUTE, 'UTF-8')); } function utf8_check_encoding($str) { return $str === utf8_scrub($str); } function utf8_ord($char) { $lead = ord($char[0]); if ($lead < 0x80) { return $lead; } else if ($lead < 0xE0) { return (($lead & 0x1F) << 6) | (ord($char[1]) & 0x3F); } else if ($lead < 0xF0) { return (($lead & 0xF) << 12) | ((ord($char[1]) & 0x3F) << 6) | (ord($char[2]) & 0x3F); } else { return (($lead & 0x7) << 18) | ((ord($char[1]) & 0x3F) << 12) | ((ord($char[2]) & 0x3F) << 6) | (ord($char[3]) & 0x3F); } }
Версия расширения PHP:
#include "ext/standard/html.h" #include "ext/standard/php_smart_str.h" const zend_function_entry utf8_string_functions[] = { PHP_FE(utf8_char_code_at, NULL) PHP_FE_END }; PHP_FUNCTION(utf8_char_code_at) { char *str; int len; long index; unsigned int code_point; long i; int status; size_t pos = 0, old_pos = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &str, &len, &index) == FAILURE) { return; } for (i = 0; pos < len; ++i) { old_pos = pos; code_point = php_next_utf8_char((const unsigned char *) str, (size_t) len, &pos, &status); if (i == index) { if (status == SUCCESS) { RETURN_LONG(code_point); } else { RETURN_NULL(); } } } RETURN_NULL(); }
Пытаться:
function uniord($c) { $h = ord($c{0}); if ($h <= 0x7F) { return $h; } else if ($h < 0xC2) { return false; } else if ($h <= 0xDF) { return ($h & 0x1F) << 6 | (ord($c{1}) & 0x3F); } else if ($h <= 0xEF) { return ($h & 0x0F) << 12 | (ord($c{1}) & 0x3F) << 6 | (ord($c{2}) & 0x3F); } else if ($h <= 0xF4) { return ($h & 0x0F) << 18 | (ord($c{1}) & 0x3F) << 12 | (ord($c{2}) & 0x3F) << 6 | (ord($c{3}) & 0x3F); } else { return false; } } echo uniord('Ą');
Это должно быть эквивалентно JavaScript charCodeAt()
основанному на работе @ hakre, но исправлено, чтобы на самом деле работать так же, как JavaScript (во всех смыслах, которые я мог придумать для тестирования):
function charCodeAt($string, $offset) { $string = substr($string, $offset, 1); list(, $ret) = unpack('S', mb_convert_encoding($character, 'UTF-16LE')); return $ret; }
Здесь есть одна функция ord_utf8 : https://stackoverflow.com/a/42600959/7558876
Эта функция выглядит так (принимаем строку и возвращаем целое число)
<?php function ord_utf8($s){ return (int) ($s=unpack('C*',$s[0].$s[1].$s[2].$s[3]))&&$s[1]<(1<<7)?$s[1]: ($s[1]>239&&$s[2]>127&&$s[3]>127&&$s[4]>127?(7&$s[1])<<18|(63&$s[2])<<12|(63&$s[3])<<6|63&$s[4]: ($s[1]>223&&$s[2]>127&&$s[3]>127?(15&$s[1])<<12|(63&$s[2])<<6|63&$s[3]: ($s[1]>193&&$s[2]>127?(31&$s[1])<<6|63&$s[2]:0))); }
И один быстрый chr_utf8 здесь: https://stackoverflow.com/a/42510129/7558876
Эта функция выглядит так (accept integer и возвращает строку)
<?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):''))); }
Проверьте ссылки, если вы хотите один пример …