我正在尝试调试为什么我的UTF-8在脚本中无法正常工作。这是原始代码:
$lc_custom{"À propos de l'italie, en français"} = "foo bar";
$lc_custom{"Здоровье"} = "foo bar";
$lc_custom{"дерьмо"} = "foo bar";
$lc_custom{"sécurité"} = "foo bar";
$lc_custom{"security"} = "foo bar";
$lc_custom{"health"} = "foo bar";
$lc_custom{"french"} = "foo bar";
$lc_custom{"ábc"} = "foo bar";
$lc_custom{"crap"} = "foo bar";
my $text_repl = '| (' . join('|', map { my $v = quotemeta; $v = '\b'.$v if $v =~ /^\w/; $v .= '\b' if $v =~ /\w$/ } sort { length($b) <=> length($a) } keys %lc_custom) . ')';
我得到的调试:
$VAR1 = {
'foo' => '| (\\�\\�\\ propos\\ de\\ l\\\'italie\\,\\ en\\ fran\\�\\�ais\\b||||\\bsecurity\\b|\\bhealth\\b|\\bfrench\\b|\\�\\�bc\\b|\\bcrap\\b)'
};
这是我的修订版,其中包含更多调试信息:
my $text_repl = '| (' . join('|', map {
print "FOO BAR: $_ \n";
my $v = $_;
$v = '\b' . $v if $v =~ /^\w/;
$v .= '\b' if $v =~ /\w$/
} sort { length($b) <=> length($a) } keys %lc_custom) . ')';
我得到:
FOO BAR: À propos de l'italie, en français
FOO BAR: Здоровье
FOO BAR: дерьмо
FOO BAR: sécurité
FOO BAR: security
FOO BAR: health
FOO BAR: french
FOO BAR: ábc
FOO BAR: crap
$VAR1 = {
'foo' => '| (\\QÀ propos de l\'italie, en français\\E\\b||||\\b\\Qsecurity\\E\\b|\\b\\Qhealth\\E\\b|\\b\\Qfrench\\E\\b|ábc\\E\\b|\\b\\Qcrap\\E\\b\\E)'
};
带有俄语时,似乎所有按键都不喜欢工作。会有什么原因吗?
更新:根据要求,使用以下代码是这样的:
use utf8;
my $test = '| (' . join('|', map { my $v = quotemeta; $v = '\b'.$v if $v =~ /^\w/; $v .= '\b' if $v =~ /\w$/ } sort { length($b) <=> length($a) } keys %lc_custom) . ')';
use Data::Dumper;
$Data::Dumper::Useqq = 1;
print Dumper({ BLA => $test });
给出:
"BLA" => "| (\\\303\\\200\\ propos\\ de\\ l\\'italie\\,\\ en\\ fran\\\303\\\247ais\\b||||\\bsecurity\\b|\\bhealth\\b|\\bfrench\\b|\\\303\\\241bc\\b|\\bcrap\\b)"
解码您的输入;编码您的输出。问题源于缺乏前者。的键%lc_custom
是使用UTF-8编码的文本字符串。通常,您不想使用编码的文本。您想使用解码后的文本。
无论quotemeta
和\w
正则表达式字符类希望提供解码的文本。将编码的文本传递给他们没有任何意义。但这就是您正在做的。
让我们看一个简单的例子。
use Data::Dumper qw( Dumper );
$Data::Dumper::Useqq = 1;
# "д♠" encoded using UTF-8 (encoded text).
my $utf8 = "\320\264\342\231\240";
say length($utf8);
print Dumper($utf8);
print Dumper(quotemeta($utf8));
say length(quotemeta($utf8));
say "";
# "д♠" as decoded text (Unicode Code Points).
my $ucp = "\x{434}\x{2660}";
say length($ucp);
print Dumper($ucp);
print Dumper(quotemeta($ucp));
say length(quotemeta($ucp));
5
$VAR1 = "\320\264\342\231\240";
$VAR1 = "\320\264\342\\\231\\\240";
7
2
$VAR1 = "\x{434}\x{2660}";
$VAR1 = "\x{434}\\\x{2660}";
3
请注意,quotemeta($utf8)
在“♠”的编码中间插入了2个反斜杠,在其之前没有一个反斜杠。另一方面,quotemeta($ucp)
在两个字符之间添加了一个反斜杠。
简而言之,您将垃圾传递给quotemeta
,而您又将垃圾带回。
Perl期望其源代码使用ASCII编码,除非您通过使用告诉它使用UTF-8编码use utf8;
。
use 5.014; # Or: use strict; use feature qw( say unicode_strings );
use warnings;
# Tell Perl the source code is encoded using UTF-8.
use utf8;
# Tell Perl the terminal provides/expects UTF-8.
# Also sets the default for `open`.
use open ':std', ':encoding(UTF-8)';
use Data::Dumper qw( Dumper );
$Data::Dumper::Useqq = 1;
# From the question, verbatim.
my %lc_custom;
$lc_custom{"À propos de l'italie, en français"} = "foo bar";
$lc_custom{"Здоровье"} = "foo bar";
$lc_custom{"дерьмо"} = "foo bar";
$lc_custom{"sécurité"} = "foo bar";
$lc_custom{"security"} = "foo bar";
$lc_custom{"health"} = "foo bar";
$lc_custom{"french"} = "foo bar";
$lc_custom{"ábc"} = "foo bar";
$lc_custom{"crap"} = "foo bar";
# From the question, verbatim.
my $text_repl = '| (' . join('|', map { my $v = quotemeta; $v = '\b'.$v if $v =~ /^\w/; $v .= '\b' if $v =~ /\w$/ } sort { length($b) <=> length($a) } keys %lc_custom) . ')';
say $text_repl;
print Dumper($text_repl);
输出:
| (\bÀ\ propos\ de\ l\'italie\,\ en\ français\b|\bЗдоровье\b|\bsécurité\b|\bsecurity\b|\bhealth\b|\bдерьмо\b|\bfrench\b|\bcrap\b|\bábc\b)
$VAR1 = "| (\\b\x{c0}\\ propos\\ de\\ l\\'italie\\,\\ en\\ fran\x{e7}ais\\b|\\b\x{417}\x{434}\x{43e}\x{440}\x{43e}\x{432}\x{44c}\x{435}\\b|\\bs\x{e9}curit\x{e9}\\b|\\bsecurity\\b|\\bhealth\\b|\\b\x{434}\x{435}\x{440}\x{44c}\x{43c}\x{43e}\\b|\\bfrench\\b|\\bcrap\\b|\\b\x{e1}bc\\b)";
请注意,此unicode_strings
功能修复了可能阻止À
匹配的错误\w
。use 5.014;
启用该功能(以及更多功能)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句