将Unicode转换为HTML实体十六进制

6

如何将Unicode字符串转换为HTML实体?(HEX而不是十进制)

例如,将Français转换为Français


1
你需要这个做什么?它应该永远不是必要的... - Pekka
4
具体取决于使用的Unicode编码。例如,在PHP中,mb_convert_encoding($utf_8, 'HTML-ENTITIES', 'UTF-8'); 可以用于处理UTF-8编码的Unicode字符串。如果您需要十六进制编码,则链接答案向您展示了如何捕获所有这些内容(从UTF-8字符串中),您只需要运行您的十六进制编码即可。 - hakre
1
你的问题不是很明确。如果我理解正确,输出应该是Français而不是Français - hakre
2
@Pekka웃 - 我刚在2015年发现了一个供应商API,需要纯US-ASCII XML请求来处理与Unicode相关的功能。 叹气 - Álvaro González
@ÁlvaroG.Vicario 哎呀!!! - Pekka
显示剩余2条评论
7个回答

11

对于相关问题中缺失的十六进制编码:

$output = preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function ($match) {
    list($utf8) = $match;
    $binary = mb_convert_encoding($utf8, 'UTF-32BE', 'UTF-8');
    $entity = vsprintf('&#x%X;', unpack('N', $binary));
    return $entity;
}, $input);

这与@Baba的答案类似,使用UTF-32BE,然后使用unpackvsprintf进行格式化。如果您更喜欢iconv而不是mb_convert_encoding,那么也类似:
$output = preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function ($match) {
    list($utf8) = $match;
    $binary = iconv('UTF-8', 'UTF-32BE', $utf8);
    $entity = vsprintf('&#x%X;', unpack('N', $binary));
    return $entity;
}, $input);

我觉得这种字符串操作比 获取HTML实体的十六进制代码 更加清晰易懂。

太棒了!我使用它来编码 CKEditors 输出,将我的 HTML 实体转换为 Unicode 符号。 - Daniel
这帮助我在一个 ISO-8859-1 网站上显示表情符号。首先,我使用这种方法将其转换为十六进制,然后可以将其保存在数据库中,并在网站和应用程序中的 Webview 中显示它。非常好。 - Jette

8
您的字符串看起来像是UCS-4编码,您可以尝试使用该编码。
$first = preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function ($m) {
    $char = current($m);
    $utf = iconv('UTF-8', 'UCS-4', $char);
    return sprintf("&#x%s;", ltrim(strtoupper(bin2hex($utf)), "0"));
}, $string);

输出
string 'Français' (length=13)

如果我想将 Fran 转换为十六进制,我应该使用哪种编码? - mrdaliri
1
echo bin2hex("Fran"); ..你不需要为此进行编码。 - Baba

5
首先,当我最近遇到这个问题时,我通过确保我的代码文件、数据库连接和数据库表都是UTF-8来解决它,然后简单地回显文本。如果必须转义来自数据库的输出,请使用htmlspecialchars()而不是htmlentities(),以便UTF-8符号保持原样而不被尝试转义。
我想记录一种替代解决方案,因为它为我解决了类似的问题。我使用PHP的utf8_encode()来转义“特殊”字符。
我想将它们转换为HTML实体进行显示,我编写了这段代码,因为我想尽可能避免使用iconv或这样的函数,因为并非所有环境都有它们(如果不是这样,请纠正我!)
function unicode2html($string) {
    return preg_replace('/\\\\u([0-9a-z]{4})/', '&#x$1;', $string);
}

$foo = 'This is my test string \u03b50';
echo unicode2html($foo);

希望这能帮到有需要的人 :- )

0

这是一个类似于@hakre(2012年11月8日0:35)的解决方案,但是使用HTML实体名称:

$output = preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function ($match) {
    list($utf8) = $match;
    $char = htmlentities($utf8, ENT_HTML5 | ENT_IGNORE);
    if ($char[0]!=='&' || (strlen($char)<2)) {
        $binary = mb_convert_encoding($utf8, 'UTF-32BE', 'UTF-8');
        $char = vsprintf('&#x%X;', unpack('N', $binary));
    } // (else $char is "&entity;", which is better)
    return $char;
}, $input);

$input = "Ob\xC3\xB3z w\xC4\x99drowny Ko\xC5\x82a";
// => $output: "Ob&oacute;z w&eogon;drowny Ko&lstrok;a"
//while @hakre/@Baba both codes:
// => $output: "Ob&#xF3;z w&#x119;drowny Ko&#x142;a"

但总是遇到了不正确的UTF-8问题,如:

$input = "Ob\xC3\xB3z w\xC4\x99drowny Ko\xC5\x82a - ok\xB3adka";
// means "Ob&oacute;z w&eogon;drowny Ko&lstrok;a -  - ok&lstrok;adka" in html ("\xB3" is ISO-8859-2/windows-1250 "ł")

但是在这里

// => $output: (empty)

还有@hakre的代码... :(

很难找出原因,我知道的唯一解决方案(也许有人知道更简单的方法?请告诉我):

function utf_entities($input) {
$output = preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function ($match) {
    list($utf8) = $match;
    $char = htmlentities($utf8, ENT_HTML5 | ENT_IGNORE);
    if ($char[0]!=='&' || (strlen($char)<2)) {
        $binary = mb_convert_encoding($utf8, 'UTF-32BE', 'UTF-8');
        $char = vsprintf('&#x%X;', unpack('N', $binary));
    } // (else $char is "&entity;", which is better)
    return $char;
}, $input);
if (empty($output) && (!empty($input))) { // Trouble... Maybe not UTF-8 code inside UTF-8 string...
    
    /* Processing string against not UTF-8 chars... */
    $output = ''; // New - repaired
    for ($i=0; $i<strlen($input); $i++) {
        if (($char = $input[$i])<"\x80") {
                $output .= $char;
            } else { // maybe UTF-8 (0b ..110xx..) or not UTF-8 (i.e. 0b11111111 etc.)
                $j = 0; // how many chars more in UTF-8
                $char = ord($char);
                do { // checking first UTF-8 code char bits
                    $char = ($char << 1) % 0x100;
                    $j++;
                } while (($j<4 /* 6 before RFC 3629 */)&& (($char & 0b11000000) === 0b11000000));
                $k = $i+1;
                if ($j<4 /* 6 before RFC 3629 */ && (($char & 0b11000000) === 0b10000000)) { // maybe UTF-8...
                    for ($k=$i+$j; $k>$i && ((ord($input[$k]) & 0b11000000) === 0b10000000); $k--) ; // ...checking next  bytes for valid UTF-8 codes
                }
                if ($k>$i || ($j>=4 /* 6 before RFC 3629 */) || (($char & 0b11000000) !== 0b10000000)) {    // Not UTF-8
                    $output .= '&#x'.dechex(ord($input[$i])).';'; // "&#xXX;"
                } else { // UTF=8 !
                    $output .= substr($input, $i, 1+$j);
                    $i += $j;
                }
            }
    }
    return utf_entities($output); // recursively after repairing
}
return $output;
}

I.e.:

echo utf_entities("o\xC5\x82a - k\xB3a"); // o&lstrok;a - k&#xb3;a - UTF-8 + fixed
echo utf_entities("o".chr(0b11111101).chr(0b10111000).chr(0b10111000).chr(0b10111000).chr(0b10111000).chr(0b10111000)."a");
// o&#xf1;&#xb8;&#xb8;&#xb8;&#xb8;&#xb8;a - invalid UTF-8 (6-bytes UTF-8 valid before RFC 3629), fixed
echo utf_entities("o".chr(0b11110001).chr(0b10111000).chr(0b10111000).chr(0b10111000)."a - k\xB3a");
// o&#x78E38;a - k&#xb3;a - UTF-8 + fixed ("\xB3")
echo utf_entities("o".chr(0b11110001).chr(0b10111000).chr(0b10111000).chr(0b10111000)."a");
// o&#x78E38;a - valid UTF-8!
echo utf_entities("o".chr(0b11110001).'a'.chr(0b10111000).chr(0b10111000)."a");
// o&#xf1;a&#xb8;&#xb8;a - invalid UTF-8, fixed

0

请参考如何在PHP中获取Unicode代码点的字符?,其中提供了一些代码,使您可以执行以下操作:

示例用法

echo "Get string from numeric DEC value\n";
var_dump(mb_chr(50319, 'UCS-4BE'));
var_dump(mb_chr(271));

echo "\nGet string from numeric HEX value\n";
var_dump(mb_chr(0xC48F, 'UCS-4BE'));
var_dump(mb_chr(0x010F));

echo "\nGet numeric value of character as DEC string\n";
var_dump(mb_ord('ď', 'UCS-4BE'));
var_dump(mb_ord('ď'));

echo "\nGet numeric value of character as HEX string\n";
var_dump(dechex(mb_ord('ď', 'UCS-4BE')));
var_dump(dechex(mb_ord('ď')));

echo "\nEncode / decode to DEC based HTML entities\n";
var_dump(mb_htmlentities('tchüß', false));
var_dump(mb_html_entity_decode('tch&#252;&#223;'));

echo "\nEncode / decode to HEX based HTML entities\n";
var_dump(mb_htmlentities('tchüß'));
var_dump(mb_html_entity_decode('tch&#xFC;&#xDF;'));

echo "\nUse JSON encoding / decoding\n";
var_dump(codepoint_encode("tchüß"));
var_dump(codepoint_decode('tch\u00fc\u00df'));

输出

Get string from numeric DEC value
string(4) "ď"
string(2) "ď"

Get string from numeric HEX value
string(4) "ď"
string(2) "ď"

Get numeric value of character as DEC int
int(50319)
int(271)

Get numeric value of character as HEX string
string(4) "c48f"
string(3) "10f"

Encode / decode to DEC based HTML entities
string(15) "tch&#252;&#223;"
string(7) "tchüß"

Encode / decode to HEX based HTML entities
string(15) "tch&#xFC;&#xDF;"
string(7) "tchüß"

Use JSON encoding / decoding
string(15) "tch\u00fc\u00df"
string(7) "tchüß"

0

这是一种在其他答案中的思路基础上构建而成的替代方法,不依赖于mbstring或iconv。(实体使用十进制表示,但可以通过在返回之前调用bin2hex来轻松地改为十六进制,并且当然还要在字符串中添加一个'x'。如果这对您是必需的话;当我发现这个问题时,对我来说并不是必需的。)

/** 
 * Convert all non-ascii unicode (utf-8) characters in a string to their HTML entity equivalent.
 * 
 * Only UTF-8 is supported, as we don't have access to mbstring.
 */
function unicode2html($string) {
    return preg_replace_callback('/[^\x00-\x7F]/u', function($matches){
        // Adapted from https://www.php.net/manual/en/function.ord.php#109812
        $offset = 0;
        $code = ord(substr($matches[0], $offset,1));
        if ($code >= 128) {        //otherwise 0xxxxxxx
            if ($code < 224) $bytesnumber = 2;                //110xxxxx
            else if ($code < 240) $bytesnumber = 3;        //1110xxxx
            else if ($code < 248) $bytesnumber = 4;    //11110xxx
            $codetemp = $code - 192 - ($bytesnumber > 2 ? 32 : 0) - ($bytesnumber > 3 ? 16 : 0);
            for ($i = 2; $i <= $bytesnumber; $i++) {
                $offset ++;
                $code2 = ord(substr($matches[0], $offset, 1)) - 128;        //10xxxxxx
                $codetemp = $codetemp*64 + $code2;
            }
            $code = $codetemp;
        }
        return "&#$code;";
    }, $string);
}

0

你也可以使用 mb_encode_numericentity,它被 PHP 4.0.6+(PHP文档链接)支持。

function unicode2html($value) {
    return mb_encode_numericentity($value, [
    //  start codepoint
    //  |       end codepoint
    //  |       |       offset
    //  |       |       |       mask
        0x0000, 0x001F, 0x0000, 0xFFFF,
        0x0021, 0x002C, 0x0000, 0xFFFF,
        0x002E, 0x002F, 0x0000, 0xFFFF,
        0x003C, 0x003C, 0x0000, 0xFFFF,
        0x003E, 0x003E, 0x0000, 0xFFFF,
        0x0060, 0x0060, 0x0000, 0xFFFF,
        0x0080, 0xFFFF, 0x0000, 0xFFFF
    ], 'UTF-8', true);
}

通过这种方式,还可以指定要将哪些字符范围转换为十六进制实体,哪些保留为字符。

使用示例:

$input = array(
    '"Meno più, PIÙ o meno"',
    '\'ÀÌÙÒLÈ PERCHÉ perché è sempre così non si sà\'',
    '<script>alert("XSS");</script>',
    '"`'
);

$output = array();
foreach ($input as $str)
    $output[] = unicode2html($str)

结果:

$output = array(
    '&#x22;Meno pi&#xF9;&#x2C; PI&#xD9; o meno&#x22;',
    '&#x27;&#xC0;&#xCC;&#xD9;&#xD2;L&#xC8; PERCH&#xC9; perch&#xE9; &#xE8; sempre cos&#xEC; non si s&#xE0;&#x27;',
    '&#x3C;script&#x3E;alert&#x28;&#x22;XSS&#x22;&#x29;;&#x3C;&#x2F;script&#x3E;',
    '&#x22;&#x60;'
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接