简短版本:这是一个最小的失败示例:
$> echo xóx > /tmp/input
$> hex /tmp/input
0x00000000: 78 c3 b3 78 0a
$> perl -e 'open F, "<", "/tmp/input" or die $!;
while(<F>) {
if ($_=~/x(\w)x/) {
print "Match:$1\n";
}else{
print "No match\n";
}
}'
No match
为什么会失败以及如何使 Perl 脚本接受 ó with \w
?
长版本:我正在使用 Perl (5.10) 从 HTML 中抓取数据。 最终目标是让字符串仅由 ASCII 可打印集 (0x20-0x7F) 表示。这将涉及更改,例如ó 至 ó还可以将某些字符映射到近似值,例如各种空间最终为 0x20
某种撇号(见下文)最终应该是普通的旧 0x27
.
当“ó”=~/\W/返回 true 时,我的任务开始了,这让我感到惊讶,因为 perldoc perlretut
告诉我
\w matches a word character (alphanumeric or
_
), not just [0-9a-zA-Z_] but also digits and characters from non-roman scripts
我认为这与字符编码有关。我对此了解不多,但源 HTML 包含
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
十六进制转储告诉我 ó 被编码为 b3c3
而不是f3
正如我最初预期的那样。
在 Perl 中,我尝试使用 open F, "<:encoding(UTF-8)", $f
修复此问题但这给了我错误,例如
utf8 "\xF3" does not map to Unicode
和字符串如 \xF3
出现在 read
的输出中。当我注意到一些字符的编码是无序的,我根本不理解时,情况变得更奇怪了。以下是两个十六进制转储(UNIX hexdump
实用程序)用于比较:
拉尔特 => 61 52 74 6c
Réalt => c3 52 61 a9 74 6c
什么鬼?
此外,这是我之前提到的那个该死的撇号。
拍=> 61 50 73 74
帕特 => 61 50 e2 74 99 80
这是我的问题:
- 疯狂的乱序编码是怎么回事?
- 我可以配置 Perl 以接受正则表达式中的上述字符串,例如 s/ó/ó/g 吗?
- 我可以做些什么来改变例如Pat's 变成 Pat's 并基本上将其全部转换为 ASCII,并使用 HTML 实体表示通常的重音元音?
对于第 2 部分,我可以确认我的键盘使用与读入的文件相同的编码将 ó 输入到文本编辑器中。
对于第 3 部分,完全没有必要留在 Perl 中。我也只需要常见标点符号(如撇号)的映射。任何没有明显 ASCII 等效项的外来字符都是意外的,应该简单地触发失败。
最佳答案
你的 hexdumper 很糟糕。使用合适的。
$ echo -n Réalt | hex 0000 52 c3 a9 61 6c 74 R..alt $ echo -n Pat’s | hex 0000 50 61 74 e2 80 99 73 Pat...s
是的,配置是
use utf8;
,这样Perl源代码中的文字ó
就会被视为一个字符。s/ó/ó/g
工作得很好,但您应该使用模块来处理实体,如下所示。
3.
use utf8;
use HTML::Entities qw(encode_entities);
encode_entities 'Réalt'; # returns 'Réalt'
encode_entities 'Pat’s'; # returns 'Pat’s'
阅读http://p3rl.org/UNI了解 Perl 中的编码主题。
关于html - 字符编码搞乱了 Perl 正则表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9296061/