我想在一些字符串中删除变音符号.tr///应该做的但是失败了(见下文).我以为我有一个编码/解码问题,但我发现我的s///工作正如我所料.有人可以解释一下原因吗?
以下是我得到的结果示例:
my $str1 = 'èîü';
my $str2 = $str1;
$str1 =~ tr/î/i/;
print "$str1\n"; # => i?iii?
$str2 =~ s/î/i/;
print "$str2\n"; # => èiü
Run Code Online (Sandbox Code Playgroud)
请注意,tr///还修改了字符串的第一个和第三个字符,而不仅仅是中间字符.
编辑:我使用Ubuntu 16.04和Mate桌面环境.
小智 18
当你没有use utf8;,但是你正在使用utf8文本编辑器查看代码时,你没有像perl看到的那样看到它.你认为你在你的左半边单个字符s///和tr///,但因为它是多个字节,perl的将其视为多个字符.
你认为perl看到了什么:
my $str1 = "\xE8\xEE\xFC";
my $str2 = $str1;
$str1 =~ tr/\xEE/i/;
print "$str1\n";
$str2 =~ s/\xEE/i/;
print "$str2\n";
Run Code Online (Sandbox Code Playgroud)
perl实际上看到了什么:
my $str1 = "\xC3\xA8\xC3\xAE\xC3\xBC";
my $str2 = $str1;
$str1 =~ tr/\xC3\xAE/i/;
print "$str1\n";
$str2 =~ s/\xC3\xAE/i/;
print "$str2\n";
Run Code Online (Sandbox Code Playgroud)
因为s///,因为没有一个字符是正则表达式运算符,所以你只是在进行子字符串搜索.您正在搜索多字符子字符串.而你发现它,因为s///在你的字符串文字中也发生了同样的事情:你认为那里的字符确实不存在,但是多字符序列是.
在tr///另一方面,多个字符不被视为一个序列,它们会被视为一组.每个字符(字节)在找到时单独处理.这并不能得到你想要的结果,因为改变utf8字符串的单个字节绝不是你想要的.
您可以运行简单的面向ASCII的子字符串搜索,对utf8一无所知,并在utf8字符串上获得正确的结果,这被认为是utf8的良好向后兼容功能,而不是像ucs2/utf16或ucs4这样的其他编码.
解决方案是告诉perl通过添加使用UTF-8对源进行编码use utf8;.您还需要对输出进行编码以匹配终端所期望的输出.
use utf8; # The source is encoded using UTF-8.
use open ':std', ':encoding(UTF-8)'; # The terminal provides/expects UTF-8.
my $str1 = 'èîü';
my $str2 = $str1;
$str1 =~ tr/î/i/;
print "$str1\n";
$str2 =~ s/î/i/;
print "$str2\n";
Run Code Online (Sandbox Code Playgroud)