【问题标题】:case insensitive regex matching not working in perl不区分大小写的正则表达式匹配在 perl 中不起作用
【发布时间】:2017-01-12 09:36:03
【问题描述】:

我在 perl 中的正则表达式模式正确匹配区分大小写的字符串,但不是大小写不同的字符串。我正在解析一个 CSV 文件,其中第一行是国家名称,其他行是该国家/地区的缩写或常见的其他拼写。

示例:CSV 的第 1 列是美国、美国、美国、美国。第 2 列是:墨西哥、MX、MEX。

这是完整的代码::

    #!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper qw(Dumper);

my $filename = 'countrycodes.csv';
my $line;
my @rowStrings;
my @rows;
my @columns;

这是我用来测试代码的字符串:

my $string = "Mex, MEX, USA, usa, US, MX, CAN, Canada";

open(my $fh, '<', $filename) or die "Can't open $filename: $!";

$line = <$fh>;
@rowStrings = split("\r", $line);

#make rows strings into arrays
foreach my $i (0..$#rowStrings){
    $rows[$i] = [split(",",$rowStrings[$i])];
}


my $columnCount = values scalar $rows[0];

print "column count: $columnCount \n";

#create array for each column from CSV
foreach my $column (0..$columnCount){
    foreach my $row (0..$#rows){
        $columns[$column][$row] =  $rows[$row][$column];
        if ($columns[$column][$row]) {
        }
    }

}

在这里,我正在浏览缩写/拼写数组并寻找匹配项。从数组中搜索任何缩写,并将它们替换为 CSV 文件 ($head) 中的标题/国家/地区名称。

for my $col (0..$#columns-1){
    my $head = $columns[$col][0];
    for my $ro (1..$#rows){
        if ($columns[$col][$ro]){
            $string =~ s/\s$columns[$col][$ro],/ $head,/i;
            print $string . "\n";
        }
    }

}

这是作为最终结果的终端输出:

Mex, Mexico, United States, usa, United States, Mexico, Canada, Canada

如您所见,MEX 匹配正确,因为这是它正在搜索的术语,但不是 Mex,即使我使用了 /i 修饰符。我做错了什么?

编辑:美国匹配,机器人不是美国。

作为参考,正则表达式模式是$string =~ s/\s$columns[$col][$ro],/ $head,/i

谢谢!

【问题讨论】:

  • 为什么不打印出$columns[$col][$ro] 看看它试图匹配什么。
  • 我一开始是打印出来的。我知道它与 CSV 字段的确切拼写匹配,但在大小写不同时不匹配。
  • 可能 Mex 不匹配,因为它前面没有空格,而您正在专门搜索那里的空格 \s
  • 美国呢?

标签: regex perl csv case


【解决方案1】:

我不完全理解你在做什么,但也许这会有所帮助:你的正则表达式中的 \s 尝试匹配空格,但不会匹配缺少空格。由于您的“Mex”位于行首,因此它前面没有空格。作为一项实验,请尝试将“Mex”移动到该行中的其他位置。

【讨论】:

    【解决方案2】:

    解析 CSV 似乎不是您的问题。 (我仍然会推荐Text::CSV。)

    假设您将语言和替代语言放在一个数组中,并且您有一个包含这些语言和替代数组的数组,您只需比较输入即可。您可能应该去除前导和尾随空格,并比较不区分大小写,但您不需要正则表达式:

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    my @countries = (   
        ['United States of America', 'US', 'USA', 'US of A', 'United States'],
        ['Mexico', 'MX', 'Mex'], 
    );
    
    my @input = ('US ', '  mx   ', ' Mexico', ' us of a');
    
    foreach my $input (@input) {  
        $input =~ s/^\s+//;
        $input =~ s/\s+$//; 
        my $found = 0;
        foreach my $country (@countries) {  
            foreach my $alternative (@$country) {
                if (lc($input) eq lc($alternative)) {  
                    print "$input is ${$country}[0]\n";
                    $found = 1;
                }
            } 
        }   
        print "did not find $input\n" unless($found);
    }
    

    【讨论】:

    • 我无法剥离替代方案周围的所有内容,因为此 CSV 还包括可能包含这些字符的人名。
    【解决方案3】:

    问题是我没有包含“g”运算符,这意味着一旦它找到了国家名称替代的一个实例,它就会停止寻找其他实例。

    通过将$string =~ s/\s$columns[$col][$ro],/ $head,/i 更改为$string =~ s/\s$columns[$col][$ro],/ $head,/ig 匹配正确。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-22
      相关资源
      最近更新 更多