Perl字符串替换伪装Unicode字符串

时间:2014-10-09 01:37:32

标签: perl unicode

当regexp仅包含ascii字符时,UTF-8编码字符串的字符串替换正常工作,但当regexp包含非ascii时会产生乱码输出。

my $str = "¿más?";

$str =~ s/[?]//g; 
print "$str\n";

==> ¿MÁS

$str =~ s/[¿]//g; 
print "$str\n";

==> MS

更新:上面的答案清楚地表明我的原始问题框架不佳。答案集中在STDOUT,但在我的实际问题中,我不打印到STDOUT。 (我只是为了简化问题陈述而这样做)。在实际问题中,我从sqlite存储中检索数据并使用数据作为文件名来搜索文件系统。当我将清理例程应用于检索到的数据时,某些文件名会出现乱码。

查看此信息的一种方法可能是进一步简化示例:

my $str = "más";

$str =~ s/[?]//g; 
print "$str\n";

==> MÁS

$str =~ s/[¿]//g; 
print "$str\n";

==> MS

现在你可以看到@ ikegami的解释不适用。关于第二个问题的问题///会产生问题。公平地说,这两个答案都解决了所述的问题 - 但任何额外的见解将不胜感激!

更新2:根据要求,添加了sprintf的矢量标志输出。注意:还将目标替换字符从¿更改为¡ - 我现在认为上面的代码(如@ikegami建议的)必须被错误地复制。

my $str = "más";
printf "%v02X\n", $str;

==> 6D.C3.A1.73

$str =~ s/[!]//g; 
printf "%v02X\n", $str;

==> 6D.C3.A1.73

print "$str\n";

==> MÁS

$str =~ s/[¡]//g; 
printf "%v02X\n", $str;

==> 6D.C3.73

print "$str\n";

==> MS

2 个答案:

答案 0 :(得分:3)

使用utf8指定源代码的编码,并使用binmode输出:

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

binmode STDOUT, ':encoding(UTF-8)';

my $str = "¿más?";

$str =~ s/[?]//g; 
print "$str\n";

$str = "¿más?";
$str =~ s/[¿]//g; 
print "$str\n";

输出:

¿más
más?

答案 1 :(得分:3)

您正在查看源代码,就好像它是UTF-8一样,但除非您告诉Perl它的UTF-8,否则它会将其视为US-ASCII。

你说你有以下内容:

my $str = "más";
printf "%v02X %s\n", $str, $str;
$str =~ s/[!]//g; 
printf "%v02X %s\n", $str, $str;
$str =~ s/[¡]//g; 
printf "%v02X %s\n", $str, $str;

但你真的给Perl提供了以下内容:

my $str = "m\xC3\xA1s";
printf "%v02X %s\n", $str, $str;   # 6D.C3.A1.73 (the UTF-8 of más)
$str =~ s/[!]//g; 
printf "%v02X %s\n", $str, $str;   # 6D.C3.A1.73 (the UTF-8 of más)
$str =~ s/[\xC2\xA1]//g;           # Replaces either of these bytes
printf "%v02X %s\n", $str, $str;   # 6D.C3.73 (garbage)

您需要以下内容:

use utf8;                             # Source is encoded using UTF-8
use open ':std', ':encoding(UTF-8)';  # Terminal provides and expects UTF-8.

my $str = "más";
printf "U+%v04X %s\n", $str, $str;   # U+006D.00E1.0073 (the Unicode of más)
$str =~ s/[¡]//g;                    # Aka s/[\x{0041}]//g
printf "U+%v04X %s\n", $str, $str;   # U+006D.00E1.0073 (the Unicode of más)

你提到你没有从源代码中获取字符串,并且你没有输出STDOUT,但修复是相同的:解码输入和编码输出。