Perl UTF8连接问题

5
我在将一个已经编码和解码的UTF8字符串连接到另一个字符串时遇到了问题。
#!/usr/bin/perl
use strict;
use utf8;
use URI::Escape;

# binmode(STDOUT, ":utf8");

my $v = "ضثصثضصثشس";
my $v2 = uri_unescape(uri_escape_utf8($v));

print "Works: $v, ", "$v2\n";
print "Fails: $v, $v2\n";
print "Works: " . "$v2\n";

以下是输出结果:

Works: ضثصثضصثشس ,ضثصثضصثشس
Wide character in print at ./testUTF8.pl line 14.
Fails: ضثصثضصثشس, ضثصثضصثشس
Works: ضثصثضصثشس

如果我使用binmode utf8,就像Perl文档建议的那样,警告信息会消失,但所有三个都失败了:
Fails: ضثصثضصثشس, ضثصثضصثشس
Fails: ضثصثضصثشس, ضثصثضصثشس
Fails: ضثصثضصثشس

发生了什么?我该如何解决这个问题?

P.S. 我需要对URL进行转义。在Perl中是否有像JavaScript一样的转义/取消转义的方法?例如,Perl给出:%D8%B6%D8%AB%D8%B5%D8%AB%D8%B6%D8%B5%D8%AB%D8%B4%D8%B3

当我使用JavaScript对相同的文本进行转义时,我得到的是:%u0636%u062B%u0635%u062B%u0636%u0635%u062B%u0634%u0633

2个回答

5

URI::Escape的文档中:

uri_unescape($string,...)
返回一个字符串,其中每个%XX序列都被实际字节(八位元组)替换。

不会将结果字节解释为UTF-8,也不会对其进行解码,您需要手动完成此操作:

use Encode qw/decode_utf8/;

# untested
my $v2 = decode_utf8 uri_unescape uri_escape_utf8 $v;
...

有没有办法在 Perl 中像 JavaScript 一样进行转义/反转义?例如,Perl 给了我:%D8%B6%D8%AB%D8%B5%D8%AB%D8%B6%D8%B5%D8%AB%D8%B4%D8%B3 --这可以通过以下方式进行反转义:ضثصثضصثشس --当我使用 JavaScript 进行转义时,我得到的是:%u0636%u062B%u0635%u062B%u0636%u0635%u062B%u0634%u0633 - DemiImp
1
@DemiImp,这太奇怪了。这不是合法的application/x-www-form-urlencoded编码,浏览器在从表单构建URL时必须使用它。 - ikegami

3

uri_unescapeuri_escape的反操作。它不假设字节代表一个UTF-8字符串。

并没有提供uri_escape_utf8的反操作。或许是为了处理错误?

#!/usr/bin/perl
use strict;
use utf8;                     # Source code is UTF-8 encoded.
use open ':std', ':utf8';     # Terminal expects UTF-8.
use URI::Escape;

my $ov = "ضثصثضصثشس";

my $uri_comp = uri_escape_utf8($ov);

my $nv = uri_unescape($uri_comp);
utf8::decode($nv) or die;

print "$ov -> $uri_comp -> $nv\n";

ضثصثضصثشس -> %D8%B6%D8%AB%D8%B5%D8%AB%D8%B6%D8%B5%D8%AB%D8%B4%D8%B3 -> ضثصثضصثشس

使用 use open ':std', ':utf8'; 命令,对 STDIN、STDOUT 和 STDERR 进行二进制模式设置,并为文件句柄指定默认编码层。 - ikegami
4
@Nemo,“Encode::decode”可以处理“任何”编码,而后者仅支持UTF-8。正如您省略的文本所解释的那样,“处理除UTF-8之外的编码”是文档中“通用目的”的含义。还有四个区别:1)前者返回解码后的字符串;后者原地解码。2)前者可以解码无效的字符串(通过使用替换字符);后者会返���错误或抛出异常。3)前者可能比后者慢。4)前者需要一个核心模块;后者是内置的。 - ikegami

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