【问题标题】:Perl - Check if any elements in each different array matches a variablePerl - 检查每个不同数组中的任何元素是否与变量匹配
【发布时间】:2013-04-03 18:04:44
【问题描述】:

我有一个问题希望有人能帮忙解决(为了解释我正在尝试做的事情,我做了很大的简化)...

我有三个不同的数组:

my @array1 =  ("DOG","CAT","HAMSTER");
my @array2 =  ("DONKEY","FOX","PIG", "HORSE");
my @array3 =  ("RHINO","LION","ELEPHANT");

我还有一个包含网页内容的变量(使用 WWW::Mechanize):

my $variable = $r->content;

我现在想看看每个数组中的任何元素是否在变量中找到,如果是,它来自哪个数组:

例如

if ($variable =~ (any of the elements in @array1)) {
     print "FOUND IN ARRAY1";
} elsif ($variable =~ (any of the elements in @array2)) { 
     print "FOUND IN ARRAY2";
} elsif ($variable =~ (any of the elements in @array3)) {
     print "FOUND IN ARRAY3";
}

使用数组执行此操作并遍历数组中的每个元素的最佳方法是什么?有没有更好的方法可以做到这一点?

非常感谢您的帮助,谢谢

【问题讨论】:

    标签: arrays perl loops if-statement www-mechanize


    【解决方案1】:

    您可以从数组元素中创建一个正则表达式,但您很可能希望禁用元字符并且确保您没有得到部分匹配:

    my $rx = join('\b|\b', map quotemeta, @array1);
    
    if ($variable =~ /\b$rx\b/) {
        print "matched array 1\n";
    }
    

    如果您确实想获得部分匹配,例如下面的FOXY,只需删除所有\b 序列。

    演示:

    use strict;
    use warnings;
    
    my @array1 =  ("DOG","CAT","HAMSTER");
    my @array2 =  ("DONKEY","FOX","PIG", "HORSE");
    my @array3 =  ("RHINO","LION","ELEPHANT");
    
    my %checks = (
        array1 => join('\b|\b', map quotemeta, @array1),
        array2 => join('\b|\b', map quotemeta, @array2),
        array3 => join('\b|\b', map quotemeta, @array3),
    );
    
    while (<DATA>) {
        chomp;
        print "The string: '$_'\n";
        for my $key (sort keys %checks) {
            print "\t";
            if (/\b$checks{$key}\b/) {
                print "does";
            } else {
                print "does not";
            }
            print " match $key\n";
        }
    }
    
    __DATA__
    A DOG ATE MY RHINO
    A FOXY HORSEY
    

    输出:

    The string: 'A DOG ATE MY RHINO'
            does match array1
            does not match array2
            does match array3
    The string: 'A FOXY HORSEY'
            does not match array1
            does not match array2
            does not match array3
    

    【讨论】:

    • 我相信将 \b 放入连接将禁用 aho-corasick 匹配;就做\b(?:$rx)\b
    • @ysth Aho 什么?英文是什么?
    • perl 有时会使用的匹配算法 |交替固定字符串;没有它,基本上每个 |将在字符串中的每个位置尝试替代,直到匹配。 en.wikipedia.org/wiki/Aho-Corasick
    【解决方案2】:
    my $re1 = join '|', @array1;
    say "found in array 1" if $variable =~ /$re1/;
    

    对每个附加数组重复(或使用正则表达式数组和术语数组)。

    【讨论】:

    • 如果@array 的内容之一有特殊字符,比如'|'怎么办?
    • @imran:在这种情况下,my $re1 = join '|', map { "\Q$_\E" } @array1;
    • 您还必须担心部分匹配。
    • @TLP:规范是查看是否在变量中找到任何数组元素,该变量被声明为网页的内容。部分匹配是隐式可接受的,因为没有一个目标模式以&lt;html&gt; 开头或以&lt;/html&gt; 结尾。
    【解决方案3】:

    首先,如果When you find yourself adding an integer suffix to variable names, think I should have used an array.

    因此,首先我要将单词集放入 arrayrefs 数组中。这将有助于确定匹配词的来源。

    其次,我将使用Regex::PreSuf 为每个单词列表制作一个模式,因为我总是忘记正确的方法。

    第三个注意using \b in regex patterns can lead to surprising results。所以,相反,我将把内容拆分成单独的\w 字符序列。

    第四,您说“我还有一个包含网页内容的变量(使用 WWW::Mechanize)”。您想匹配 cmets 中的单词吗?在title 属性中?如果不这样做,您应该解析 HTML 文档以提取完整的纯文本或将匹配限制在某个元素或元素集内。

    然后,grep 从文本中的单词列表中找出那些在单词集中的单词,并将它们映射到它们匹配的单词集。

    #!/usr/bin/env perl
    
    use strict; use warnings;
    
    use Regex::PreSuf qw( presuf );
    
    my @wordsets = (
        [ qw( DOG CAT HAMSTER ) ],
        [ qw( DONKEY FOX PIG HORSE ) ],
        [ qw( RHINO LION ELEPHANT ) ],
    );
    
    my @patterns = map {
        my $pat = presuf(@$_);
        qr/\A($pat)\z/;
    } @wordsets;
    
    my $content = q{Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
    ad minim veniam, quis ELEPHANT exercitation ullamco laboris nisi ut aliquip
    ex ea commodo consequat. Duis aute irure dolor in reprehenderit in HAMSTER
    velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
    cupidatat non proident, sunt in DONKEY qui officia deserunt mollit anim id
    est laborum.};
    
    my @contents = split /\W+/, $content;
    
    use YAML;
    print Dump [
        map {
            my $i = $_;
            map +{$_ => $i },
            grep { $_ =~ $patterns[$i] } @contents
        } 0 .. $#patterns
    ];
    

    这里,grep { $_ =~ $patterns[$i] } @contents@contents 中提取给定单词集中的单词。然后,map +{$_ =&gt; $i } 将这些词映射到它们来自的词集。外部的map 只是循环遍历每个单词集模式。

    输出:

    --- - 仓鼠:0 - 驴:1 - 大象:2

    也就是说,您会得到一个 hashref 列表,其中每个 hashref 中的键是找到的单词,值是匹配的单词集。

    【讨论】:

      【解决方案4】:

      我假设$variable 不是一个数组,在这种情况下使用foreach 语句。

      foreach my $item (@array1) {
          if ($item eq $variable) {
              print "FOUND IN ARRAY1";
          }
      }
      

      对每个数组重复上述操作,即array2、array3...

      【讨论】:

        【解决方案5】:

        编辑:我认为您可以使用 perl 的 map 函数,如下所示:

        @a1matches = map { $variable =~ /$_/ ? $_ : (); } @array1;
        print "FOUND IN ARRAY1\n" if $#a1matches >= 0;
        
        @a2matches = map { $variable =~ /$_/ ? $_ : (); } @array2;
        print "FOUND IN ARRAY2\n" if $#a2matches >= 0;
        
        @a3matches = map { $variable =~ /$_/ ? $_ : (); } @array3;
        print "FOUND IN ARRAY3\n" if $#a3matches >= 0;
        

        一个有趣的副作用是@a1matches 包含@array1 的元素,这些元素在$variable 中。

        【讨论】:

        • 除非$variable 包含一个假值,否则它永远不会返回假。而且,你的支票被撤销了。
        • 你倒退了。他想查看$variable 中是否有任何数组元素,而不是$variable 是否在任何数组中。
        • 地图内的回报是什么?非常规。
        • @imran 你是对的,我不是那个意思(实际上它不会起作用)-我现在使用了三元运算符。谢谢大家!
        • 您仍然可以使用 grep 执行此操作:@a1matches = grep { $variable =~ /\Q$_\E/ } @array1;
        【解决方案6】:

        Regexp::Assemble 如果您喜欢使用模块,可能会有所帮助。它允许将一串正则表达式组合成一个匹配所有单个正则表达式的正则表达式。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-06-28
          • 2017-02-10
          • 1970-01-01
          • 2022-01-20
          • 1970-01-01
          • 2011-05-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多