首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >utf-8的perl二进制模式只使用\x{codepoint},而不对三个字节编码使用\x编码。

utf-8的perl二进制模式只使用\x{codepoint},而不对三个字节编码使用\x编码。
EN

Stack Overflow用户
提问于 2016-07-11 08:29:04
回答 3查看 1.9K关注 0票数 1

在UTF-8中,欧元特征为0xe282 in。

我试图在perl中使用一个字符串,并将UTF-8字符输出到STDOUT。

因此,我将我的脚本设置为UTF-8和“使用utf8;”

我把我的STDOUT设置在“双模”的UTF-8中.

一个示例脚本是:

代码语言:javascript
复制
use utf8;
binmode STDOUT, ':utf8';
print "I owe you 160\x{20ac}\n";
print "I owe you 80\xe2\x82\xac\n";  # UTF-8 encoding?

\x{codepoint}工作正常,但是编码UTF-8会给出一个错误:

代码语言:javascript
复制
I owe you 160€
I owe you 80â¬
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-07-11 09:49:50

如果您想要一个由三个字节E2 82 AC组成的字符串,您可以这样声明它:

代码语言:javascript
复制
my $bytes = "\xE2\x82\xAC";

双引号字符串中的\xXX表单使用两个十六进制数字(总是两个)来表示一个字节。

上面的字符串包含3个字节。如果将字符串传递给length函数,它将返回3:

代码语言:javascript
复制
say 'Length of $bytes is: ' . length($bytes);    # 3

Perl无法知道这三个字节是否用于表示欧元符号。它们同样可以是来自JPEG文件、ZIP文件或穿越网络的SSL编码TCP数据流的三字节序列。Perl不知道也不关心--它只有三个字节。

如果您实际上需要一个字符串(而不是字节),那么您需要以一种允许Perl使用Unicode字符的内部表示形式将它们存储在内存中的方式提供字符数据。一种方法是在源代码中以UTF8形式提供非ASCII字符。如果要这样做,则需要在脚本顶部使用use utf8命令Perl解释器将非ASCII字符串文本处理为utf8:

代码语言:javascript
复制
use utf8;

my $euro_1 = "€";

或者,您也可以使用表单\{X.}和表示Unicode码点号的1-5十六进制字符。这将声明一个相同的字符串:

代码语言:javascript
复制
my $euro_2 = "\x{20ac}";

每个字符串都包含Perl内部编码中欧元字符的多字节表示形式。Perl知道字符串是字符串,因此length函数将在每种情况下返回1(对于1个字符):

代码语言:javascript
复制
say 'Length of $euro_1 is: ' . length($euro_1);    # 1
say 'Length of $euro_2 is: ' . length($euro_2);    # 1

Perl的字符串内部表示的定义特性是用于Perl内部。如果要将数据写入文件或套接字,则需要将字符串编码为字节序列:

代码语言:javascript
复制
use Encode qw(encode);

say encode('UTF-8', $euro_1);

还可以使用binmodeopen参数来表示写入特定文件句柄的任何字符串都应该编码到特定的编码。

代码语言:javascript
复制
binmode(STDOUT, ':encoding(utf-8)');

say $euro_1;

这将只对字符串正确工作。如果我们使用原始的3字节字符串$bytes,并使用encode或IO层,那么最终会产生垃圾,因为Perl会将每个字节都转换成UTF8。所以\xE2输出为\xC3\xA2\x82输出为\xC2\x82等等。

但是,我们可以使用Encode::Decode函数将3字节$bytes字符串转换为Perl内部字符表示中的单个字符串:

代码语言:javascript
复制
use Encode qw(decode);

my $bytes = "\xE2\x82\xAC";
my $euro_3 = decode($bytes);

say 'Length of $euro_3 is ' . length($euro_3);    # 1

一个小问题:在你最初的问题中,你说20AC是欧元符号的UTF-16表示。事实上,有两种不同的UTF-16表示: UTF16BE和UTF16LE,后者使用相反的顺序:AC20

票数 5
EN

Stack Overflow用户

发布于 2016-07-11 10:00:41

作为您链接到的fileformat.info页面,Unicode欧元符号字符位于代码点20AC,可以称为U+20AC。在UTF-8中,编码为三个字节0xE2 0x82 0xAC。

若要将Unicode字符添加到字符串中,可以编写

代码语言:javascript
复制
"I owe you \x{20ac}160\n"

代码语言:javascript
复制
"I owe you \N{EURO SIGN}160\n"

代码语言:javascript
复制
"I owe you \N{U+20AC}160\n"

或者,如果在程序顶部添加use utf8,则可以添加具有相同效果的文字字符。

代码语言:javascript
复制
"I owe you €160\n"

每个字符都将向字符串中添加一个字符,并使用所需的代码点。

如果您使用

代码语言:javascript
复制
"I owe you 80\xe2\x82\xac\n"

然后,您已经创建了一个字符串,三个字符对应于UTF-8编码的欧元符号字符,这是一个非常不同的东西。您可以使用来自decode_utf8模块的Encode将这些字节转换为单个字符,但否则您将有一个UTF-8编码的字符串,这与字符串是不同的。

下面是一个示例程序

代码语言:javascript
复制
use strict;
use warnings 'all';

use open qw/ :std :encoding(UTF-8) /;

use Encode qw/ decode_utf8 :fallbacks /;

for my $s (
        "I owe you \x{20ac}160\n",
        "I owe you \N{EURO SIGN}160\n",
        "I owe you \N{U+20AC}160\n",
        do { use utf8; "I owe you €160\n" },
        decode_utf8(my $ss = "I owe you \xe2\x82\xac160\n") ) {

    print $s;
}

输出

代码语言:javascript
复制
I owe you €160
I owe you €160
I owe you €160
I owe you €160
I owe you €160

请注意,除非在源代码中使用非ASCII字符(如use utf8 ),否则不需要使用。您可以按其Unicode名称(总是在ASCII中)访问字符,如上文所示。

如果我重定向到一个文件,我可以看到它正在像预期的那样编码第一个欧元符号,0xe282ac,但是第二个正在变成0xc3a2c20x82c2ac,所以不知怎么的,它被混淆了,好像它被编码了两次。

它被编码了两次。通过为字符提供编码“xe2x82\xac”的UTF-8编码,并为输出文件句柄上的binmode对每个字符进行第二次编码,给出E2C3 A282C2 82ACC2 AC

票数 3
EN

Stack Overflow用户

发布于 2016-07-11 14:13:02

您正在构建两个不同的字符串,因此获得不同的结果也就不足为奇了。

你在执行所谓的“双重编码”。您有一个已经使用UTF-8编码的字符串,并要求Perl (使用binmodeprint)第二次对其进行编码。那是你的错误。

字符串文本"\x{20ac}"生成一个单字符字符串(0x20ac)。

代码语言:javascript
复制
$ perl -E'say length("\x{20ac}")'
1

当您使用:utf8句柄将其打印到句柄时,您是在指示Perl将这些字符视为Unicode代码点,并使用UTF-8对它们进行编码。

根据请求,Perl打印以下使用UTF-8编码的代码:

U+020AC欧元符号(欧元)

代码语言:javascript
复制
$ perl -E'binmode STDOUT, ":utf8"; print "\x{20ac}"' | od -t x1
0000000 e2 82 ac
0000003

$ perl -E'binmode STDOUT, ":utf8"; say "\x{20ac}"'
€

字符串文本"\xe2\x82\xac"生成一个三个字符的字符串(0xe2, 0x82, 0xac)。

代码语言:javascript
复制
$ perl -E'say length("\xe2\x82\xac")'
3

("\xe2\x82\xac""\x{e2}\x{82}\x{ac}"是同一回事。)

当您使用:utf8句柄将其打印到句柄时,您是在指示Perl将这些字符视为Unicode代码点,并使用UTF-8对它们进行编码。

根据请求,Perl打印以下使用UTF-8编码的代码:

U+000E2拉丁文小写字母A带回旋(A),

U+00082中断允许在这里和

U+000AC没有签名。

代码语言:javascript
复制
$ perl -E'binmode STDOUT, ":utf8"; print "\xe2\x82\xac"' | od -t x1
0000000 c3 a2 c2 82 c2 ac
0000006

$ perl -E'binmode STDOUT, ":utf8"; say "\xe2\x82\xac"'
�
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38302377

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档