Regex 当字符串包含非拉丁字符时,在制表符上使用split()函数会出现问题
我正在修改一个Perl脚本,该脚本读取一系列UCS-2LE编码的文件,其中包含制表符分隔格式的字符串,但是当字符串包含扩展拉丁字符集之外的字符时,我在拆分制表符上的字符串时遇到了问题 下面是我从这些文件中读取的示例行(以制表符分隔): 当我让脚本将这些行写入输出文件以尝试调试此问题时,它就是这样写的:Regex 当字符串包含非拉丁字符时,在制表符上使用split()函数会出现问题,regex,perl,tabs,ucs,Regex,Perl,Tabs,Ucs,我正在修改一个Perl脚本,该脚本读取一系列UCS-2LE编码的文件,其中包含制表符分隔格式的字符串,但是当字符串包含扩展拉丁字符集之外的字符时,我在拆分制表符上的字符串时遇到了问题 下面是我从这些文件中读取的示例行(以制表符分隔): 当我让脚本将这些行写入输出文件以尝试调试此问题时,它就是这样写的: ad1Ů1ĉtranscript asr turkish 它似乎无法识别土耳其字符后的制表符。只有当单词以非拉丁字符结尾(因此与制表符相邻)时,才会发生这种情况 以下是代码块的一部分,其中
ad1Ů1ĉtranscript asr turkish
它似乎无法识别土耳其字符后的制表符。只有当单词以非拉丁字符结尾(因此与制表符相邻)时,才会发生这种情况
以下是代码块的一部分,其中写入输出文件并拆分字符串:
for my $infile (@ARGV){
if (!open (INFILE, "<$infile")){
die "Couldn't open $infile.\n";
}
binmode (OUTFILE, ":utf8");
while (<INFILE>) {
chomp;
$tTot++;
if ($lineNo == 1) {
$_ = decode('UCS-2LE', $_);
}
else {
$_ = decode('UCS-2', $_);
}
$_ =~ s/[\r\n]+//g;
my @foo = split('\t');
my $orth = $foo[0];
my $tscrpt = $foo[1];
my $langCode = $foo[3];
if (exists $codeHash{$langCode}) {
unless ($tscrpt eq '') {
check($orth, $tscrpt, $langCode);
}
}
else {
print OUTFILE "Unknown language code $langCode at line $lineNo.\n";
print OUTFILE $_; # printing the string that's not being split correctly
print OUTFILE "\n";
$tBad++;
}
}
我的$infle(@ARGV){
如果(!open(infle,“您应该首先以正确的编码打开文件(我不知道这是否正确,但我相信您的话)。那么您不需要调用decode():
open(我的$fh,”多亏了大家的评论和一些进一步的研究,我找到了解决问题的方法,结果与我想象的略有不同;结果是分裂的组合()我必须在显式open语句中添加编码,而不是在for循环中使用隐式open,并跳过文件开头的前两个字节
下面是我在问题中发布的部分的正确工作代码:
for my $infile (@ARGV){
my $outfile = $infile . '.out';
# SOLUTION part 1: added explicit open statement
open (INFILE, "<:raw:encoding(UCS-2le):crlf", $infile) or die "Error opening $infile: $!";
# SOLUTION part 2: had to skip the first two bytes of the file
seek INFILE, 2, 0;
if (!open (OUTFILE, ">$outfile")) {
die "Couldn't write to $outfile.\n";
}
binmode (OUTFILE, ":utf8");
print OUTFILE "Line#\tOriginal_Entry\tLangCode\tOffending_Char(s)\n";
$tBad = 0;
$tTot = 0;
$lineNo = 1;
while (<INFILE>) {
chomp;
$tTot++;
# SOLUTION part 3: deleted the "if" block I had here before that was handling encoding
# Rest of code in the original block is the same
}
用于我的$infle(@ARGV){
我的$outfile=$infle'.out';
#解决方案第1部分:添加显式open语句
打开(填充,“$outfile”)){
die“无法写入$outfile。\n”;
}
binmode(输出文件“:utf8”);
打印输出文件“Line#\tOriginal_Entry\tLangCode\tFending_Char(s)\n”;
$tBad=0;
$tTot=0;
$lineNo=1;
而(){
咀嚼;
$tTot++;
#解决方案第3部分:删除了我之前处理编码的“if”块
#原始块中的其余代码是相同的
}
我的代码现在可以正确识别与不属于扩展拉丁语集的字符相邻的制表符字符,并在制表符上按应有的方式拆分
注意:另一种解决方案是用双引号将外来词括起来,但是,在我们的例子中,我们不能保证输入文件的格式是那样的
感谢所有发表评论并帮助我解决问题的人!您应该能够在5行以内演示拆分的问题。并且不要在更新中忽略处理输出编码的行。此外,请提供即将演示失败的输入。od-t x1文件将以表单形式提供它顺便说一句,$\=decode('UCS-2LE',$);s/^\x{FEFF}//
将是一种更简单的文件解码方法。更好的方法是使用“您的拆分到@foo
似乎与您的输出无关,只是触发了几条错误消息。s
语句下面的任何内容似乎都不会影响您的打印(未编码)$\uuuz
。顺便说一句,UCS-2le是UTF-16le的一个子集。如果你拥有的实际上是UTF-16le,那么最好使用UTF-16le进行解码。@ikegami谢谢你的提示。我将尝试使用UFT-16le打开文件。另外,因为我在这方面是新手,你能告诉我这篇文章的哪些部分没有用处吗?这样下次我就可以在没有UTF-16le的情况下简洁一些省掉重要的部分?谢谢!
open(my $fh, "<:encoding(UCS-2LE)", $file) or die "Error opening $file: $!";
while (<$fh>) {
...
}
for my $infile (@ARGV){
my $outfile = $infile . '.out';
# SOLUTION part 1: added explicit open statement
open (INFILE, "<:raw:encoding(UCS-2le):crlf", $infile) or die "Error opening $infile: $!";
# SOLUTION part 2: had to skip the first two bytes of the file
seek INFILE, 2, 0;
if (!open (OUTFILE, ">$outfile")) {
die "Couldn't write to $outfile.\n";
}
binmode (OUTFILE, ":utf8");
print OUTFILE "Line#\tOriginal_Entry\tLangCode\tOffending_Char(s)\n";
$tBad = 0;
$tTot = 0;
$lineNo = 1;
while (<INFILE>) {
chomp;
$tTot++;
# SOLUTION part 3: deleted the "if" block I had here before that was handling encoding
# Rest of code in the original block is the same
}