为什么“\ w”与Perl正则表达式中的Unicode单词字符(例如“ğ,İ,ş,ç,ö,ü”)不匹配?

时间:2012-03-15 17:30:48

标签: regex perl unicode

为什么“\ w”不匹配Perl正则表达式中的Unicode字符(例如“ğ,İ,ş,ç,ö,ü”)?

我尝试在正则表达式m{\w+}g中包含这些字符。但是,它与“ğ,İ,ş,ç,ö,ü”不匹配。

我该如何做到这一点?

use strict;
use warnings;
use v5.12;
use utf8;

open(MYINPUTFILE, "< $ARGV[0]");

my @strings;
my $delimiter;
my $extensions;
my $id;

while(<MYINPUTFILE>)
{
    my($line) = $_;
    chomp($line);
    print $line."\n";
    unshift(@strings,$line =~ /\w+/g);
    $delimiter = /[._\s]/;
    $extensions = /pdf$|doc$|docx$/;
    $id = /^200|^201/;
}

foreach(@strings){
    print $_."\n";
}

输入文件如下:

  

Çidem_Şener
  HüsnüTağlip
  ...

输出如下:

H�

sn�

Ta�

lip

�

idem_�

ener

在代码中,我尝试读取文件并获取数组中的每个字符串。 (分隔符可以是_.\s)。

3 个答案:

答案 0 :(得分:3)

确保Perl将数据视为UTF-8。

e.g。如果它嵌入在脚本本身中:

#!/usr/bin/perl

use strict;
use warnings; 
use v5.12;
use utf8;   # States that the Perl program itself is saved using utf8 encoding

say "matched" if "ğİşçöü" =~ /^\w+$/;

输出匹配。如果我删除use utf8;行,则不会。

答案 1 :(得分:3)

\w matches any of ğ İ ş ç ö ü just fine.

'ğİşçöü' =~ /\A \w+ \z/msx;     # true

您可能犯了一个错误,忘记将八位字节的输入解码为Perl字符。我怀疑你的正则表达式检查字节级别而不是字符级别的东西,就像人们期望的那样。

阅读http://p3rl.org/UNIhttp://training.perl.com/scripts/perlunicook.html,了解Perl中的编码主题。


修改

这里可能存在问题(如果没有文件内容,我无法确定):

open(MYINPUTFILE, "< $ARGV[0]");

找出文件的编码,可能是UTF-8Windows-1254。重写它,例如:

open $in, '<:utf8', $ARGV[0];
open $in, '<:encoding(Windows-1254)', $ARGV[0];

同样,由于缺少编码,将字符打印到STDOUT(程序末尾附近)同样会被打破。 ℞ 16: Declare STD{IN,OUT,ERR} to be in locale encoding显示了如何正确执行此操作的一种方法。

答案 2 :(得分:1)

Unicode可能是一个挑战,Perl有自己的特点。 基本上,Perl建立了一个围绕Unicode的所有输入/输出途径的防火墙。你必须告诉Perl I / O的路径是否有编码。如果是,则规则为任何输入的DECODE和/或任何输出的ENCODE。

解码将{encoding}中的数据转换为Perl使用的内部表示,这可能是字节和代码点的组合。

编码正好恰恰相反。

因此,实际上可以“解码”并“编码”为两种不同的编码。你只需要告诉它它是什么。编码/解码通常通过文件I / O层完成,但您可以使用Encode模块(分发的一部分)在编码之间来回手动转换。

虽然perldocs on Unicode不是轻读。

这是一个可能有助于将其可视化的示例(还有许多其他方法)。

use strict;
use warnings;
use Encode;


# This is an internalized string with these UTF-8 codepoints
# ----------------------------------------------
my $internal_string_1 = "\x{C7}\x{69}\x{64}\x{65}\x{6D}\x{5F}\x{15E}\x{65}\x{6E}\x{65}\x{72}\x{20}\x{48}\x{FC}\x{73}\x{6E}\x{FC}\x{20}\x{54}\x{61}\x{11F}\x{6C}\x{69}\x{70}";


# Open a temp file for writing as UTF-8.
# Output to this file will be automatically encoded from Perl internal to UTF-8 octets.
# Write the internal string.
# Check the file with a UTF-8 editor.
# ----------------------------------------------
open (my $out, '>:utf8', 'temp.txt') or die "can't open temp.txt for writing $!";
print $out $internal_string_1;
close $out;


# Open the temp file for readin as UTF-8.
# All input from this file will be automatically decoded as UTF-8 octets to Perl internal.
# Read/decode to a different internal string.
# ----------------------------------------------
open (my $in, '<:utf8', 'temp.txt') or die "can't open temp.txt for reading $!";
$/ = undef;
my $internal_string_2 = <$in>;
close $in;


# Change the binmode of STDOUT to UTF-8.
# Output to STDOUT will now be automatically encoded from Perl internal to UTF-8 octets.
# Capture STDOUT to a file then check with a UTF-8 editor.
# ----------------------------------------------
binmode STDOUT, ':utf8';
print $internal_string_2, "\n\n";


# Use encode() to convert an internal string to UTF-8 octets
# Format the UTF-8 octets to hex values
# Print to STDOUT
# ----------------------------------------------
my $octets = encode ("utf8", $internal_string_2);
print "Encoded (out) string -> UTF-8 (octets):\n";
print "   length  =  ".length($octets)."\n";
print "   octets  =  $octets\n";
print "   HEX val =  ";
for (split //, $octets) {
    printf ("0x%X ", ord($_));
}
print "\n\n";


# Use decode() to convert external UTF-8 octets to an internal string.
# Format the internal string to codepoints (hex values).
# Print to STDOUT.
# ----------------------------------------------
my $internal_string_3 = decode ("utf8", $octets);
print "Decoded (in) string <- UTF-8 (octets):\n";
print "   length      =  ".length($internal_string_3)."\n";
print "   string      =  $internal_string_3\n";
print "   code points =  ";
for (split //, $internal_string_3) {
    printf ("\\x{%X} ", ord($_));
}

输出

Çidem_Şener Hüsnü Tağlip

Encoded (out) string -> UTF-8 (octets):
   length  =  29
   octets  =  Ãidem_Åener Hüsnü TaÄlip
   HEX val =  0xC3 0x87 0x69 0x64 0x65 0x6D 0x5F 0xC5 0x9E 0x65 0x6E 0x65 0x72 0x20 0x48 0xC3 0xBC 0x73 0x6E 0xC3 0xBC 0x20 0x54 0x61 0xC4 0x9F 0x6C 0x69 0x70

Decoded (in) string <- UTF-8 (octets):
   length      =  24
   string      =  Çidem_Şener Hüsnü Tağlip
   code points =  \x{C7} \x{69} \x{64} \x{65} \x{6D} \x{5F} \x{15E} \x{65} \x{6E} \x{65} \x{72} \x{20} \x{48} \x{FC} \x{73} \x{6E} \x{FC} \x{20} \x{54} \x{61} \x{11F} \x{6C} \x{69} \x{70}