如何使用 Perl 包将 UTF-16 代理项对转换为 UTF-8?

How to use Perl pack to convert UTF-16 surrogate pairs to UTF-8?

提问人:WingedKnight 提问时间:6/9/2022 最后编辑:WingedKnight 更新时间:6/9/2022 访问量:202

问:

我有输入字符串,其中包含一些字符采用 UTF-16 格式并用“”转义的文本。我正在尝试在 Perl 中将所有字符串转换为 UTF-8。例如,字符串在输入中的格式可能为:\u'Alice & Bob & Carol'

'Alice \u0026 Bob \u0026 Carol'

为了做我想要的转换,我正在做...:

$str =~ s/\\u([A-Fa-f0-9]{4})/pack("U", hex($1))/eg;

...在我输入包含 UTF-16 代理项对的字符串之前,它工作正常,例如:

'Alice \ud83d\ude06 Bob'

如何修改上述用于处理 UTF-16 代理项对的代码?我真的想要一个无需使用任何其他库(JSON::XS、Encode 等)即可使用的解决方案。packpack

perl utf-8 utf-16 unicode-string unicode- 转义

评论

0赞 ikegami 6/9/2022
UTF-16是什么意思?该代码无法使用 UTF-16 输入。
0赞 ikegami 6/9/2022
假设您没有 UTF-16 但解码的文本,您将使用一个替换来查找 hi surro,然后查找 lo。使用 / 获取数字,做一些小动作,然后使用 / 创建代码点。ordunpack Wchrpack W
0赞 ysth 6/9/2022
这些肯定看起来像 Json 字符串。在我看来,除了 \u 之外,您可能会遇到其他问题,即它们被 Json 编码。只需使用 Json 解码器,不要让自己变得困难。
0赞 WingedKnight 6/9/2022
@ikegami:在输入中,所有非 ASCII 字符都以 UTF-16 开头,但已使用“\u”转义序列进行转义。
0赞 ikegami 6/9/2022
在转换为 ASCII 之前,它曾经是什么编码并不重要?UTF-8?

答:

3赞 Shawn 6/9/2022 #1

pack/unpack对 UTF-16 文本一无所知,只了解 UTF-8(和 UTF-EBCDIC)。您必须手动解码代理项对,因为您不想使用模块。

#!/usr/bin/env perl                                                                                                                                                                                                                              
use strict;
use warnings;
use open qw/:locale/;
use feature qw/say/;

my $str = 'Alice \ud83d\ude06 Bob \u0026 Carol';

# Convert surrogate pairs encoded as two \uXXXX sequences
# Only match valid surrogate pairs so adjacent non-pairs aren't counted as one
$str =~ s/\\u((?i)D[89AB]\p{AHex}{2}) # High surrogate in range 0xD800–0xDBFF
          \\u((?i)D[CDEF]\p{AHex}{2}) #  Low surrogate in range 0xDC00–0xDFFF
         /chr( ((hex($1) - 0xD800) * 0x400) + (hex($2) - 0xDC00) + 0x10000 )/xge;
# Convert single \uXXXX sequences
$str =~ s/\\u(\p{AHex}{4})/chr hex $1/ge;

say $str;

输出

Alice 😆 Bob & Carol

评论

0赞 ikegami 6/9/2022
我会反其道而行之。解码 ,然后查找 。以这种方式适用于更多输入。\u[\x{D800}-\x{DBFF}][\x{DC00}-\x{DFFF}]
0赞 Shawn 6/9/2022
以这种方式对无效字符的警告太多。
0赞 ikegami 6/9/2022
回复“Too many warnings about invalid characters that way.”,您可能没有从 to 进行必要的伴随更改。hex($x)ord($x)
0赞 ikegami 6/9/2022
该解决方案不适用于{ "a": "\\u2660" }
1赞 WingedKnight 6/10/2022
@ikegami:如果你认为你有更好的解决方案,那么你能发布代码来证明你的解决方案作为答案吗?谢谢。