【问题标题】:Match all except containing '_iq_'匹配除包含 '_iq_' 之外的所有内容
【发布时间】:2012-08-15 16:29:40
【问题描述】:

编辑:对不起!我应该在之前提到这一点。在您的回答中,请不要假设下面列出的项目是我正在搜索的目录中的唯一内容。除了指定的两个之外,这些都是我想要匹配的东西。谢谢。

这应该很容易,但我尝试的一切都没有成功。我有以下项目需要匹配:

bodipr2__ds_di_uat
bodipr2__ds_dw_uat
bodipr2__ds_iq_uat
bodipr2__ds_iq_uat_back
bodipr2__ds_itsys_uat
bodipr2__ds_ppp_uat
bodipr2__ds_psd_uat
bodipr2__ds_usage_uat
bodits2__ds_pef_tst
bodits2__ds_ppp_tst
bodits2__ds_pri_tst

除了我想省略包含_iq_ 的两个。所以我写了这样一个表达式:

bodi.*?__ds[^_iq_]

但这忽略了所有这些。如果我试试这个:

bodi.*?__ds_[^iq]

这省略了_itsys_ 之一。我猜它匹配不包含“i”或“q”的所有内容。我希望它在该位置省略不包含 '_iq_' 的内容。

我很尴尬,我什至不得不问这个问题,但如果有人能指出我正确的方向,我将不胜感激。

【问题讨论】:

    标签: regex string perl


    【解决方案1】:

    试试这个:bod[a-z\d]+__ds_(?!iq_)\w+
    我已经从http://regexr.com?31rho测试过

    【讨论】:

    • 太棒了,它确实匹配。让我快速测试一下,当我确认它在我的脚本中有效时我会接受 :)
    【解决方案2】:

    只是为了解释为什么你尝试了[^iq]不起作用,这是因为[^iq]的意思是“匹配任何一个字符,除非字符是“i”或“q”。而[^_iq_] 的含义相同,除了它也匹配“_”。

    所以,在你的情况下,

    • bodi.*?__ds[^_iq_] 会匹配其中的 100%,因为每个 sring 在“ds”之后都包含“_”,这将匹配 [^_iq_]

    • bodi.*?__ds_[^iq] 将仅匹配在“ds”之后包含字母“i”或“q”的行,这将是 - 正如您现在可以猜到的 - both _iq_ AND _itsys_ 行。

    匹配“不包含 iq”的正确方法是 Godspeed 或 FailedDev 的答案中显示的否定前瞻 (?!iq)

    【讨论】:

      【解决方案3】:

      如果有 个匹配项,您可以跳过并处理其余的:

      #!/usr/bin/env perl
      
      use strict;
      use warnings;
      
      while (<DATA>) {
          next if /^bodipr2__ds_iq_/;  # Skip if bodipr2__ds_iq_ is matched
      
          # Process data
          print;
      }
      
      __DATA__
      bodipr2__ds_di_uat
      bodipr2__ds_dw_uat
      bodipr2__ds_iq_uat
      bodipr2__ds_iq_uat_back
      bodipr2__ds_itsys_uat
      bodipr2__ds_ppp_uat
      bodipr2__ds_psd_uat
      bodipr2__ds_usage_uat
      bodits2__ds_pef_tst
      bodits2__ds_ppp_tst
      bodits2__ds_pri_tst
      

      使用grep

      #!/usr/bin/env perl
      
      use strict;
      use warnings;
      
      my @strings = qw(
        bodipr2__ds_di_uat
        bodipr2__ds_dw_uat
        bodipr2__ds_iq_uat
        bodipr2__ds_iq_uat_back
        bodipr2__ds_itsys_uat
        bodipr2__ds_ppp_uat
        bodipr2__ds_psd_uat
        bodipr2__ds_usage_uat
        bodits2__ds_pef_tst
        bodits2__ds_ppp_tst
        bodits2__ds_pri_tst
      );
      @strings = grep /^bodipr2__ds_iq_/ ? 0 : 1, @strings;
      

      【讨论】:

      • 有没有办法在我正在使用的grep函数中过滤掉它?
      【解决方案4】:

      您可以使用not 来反转:

      if (not /^bodi.*_iq_.*/) {
        print;
      }
      

      或:

      if ($line !~ /^bodi.*_iq_.*/) {
         print;
      }
      

      【讨论】:

      • 抱歉,我会更具体地解决我的问题,但是我匹配的目录中还有其他内容根本不匹配,这将导致那些过滤...
      【解决方案5】:

      这个怎么样:

          use strict;
          use warnings;
      
      
      
          for (<DATA>)
          {
              chomp;
              if (! m/bodi.*_iq_/)
              {
                  print $_ . "\n";
              }
          }
      
      __DATA__
      bodipr2__ds_di_uat
      bodipr2__ds_dw_uat
      bodipr2__ds_iq_uat
      bodipr2__ds_iq_uat_back
      bodipr2__ds_itsys_uat
      bodipr2__ds_ppp_uat
      bodipr2__ds_psd_uat
      bodipr2__ds_usage_uat
      bodits2__ds_pef_tst
      bodits2__ds_ppp_tst
      bodits2__ds_pri_tst
      

      【讨论】:

        【解决方案6】:

        这段代码:

        while ($subject =~ m/^(?:(?!_iq_).)*$/g) {
            print $&, "\n";
        }
        

        将打印除这两个字符串之外的所有内容。您可以通过在 (?!_iq_) 之后添加更多负前瞻来扩展此功能。

        示例测试:

        【讨论】:

          【解决方案7】:

          我看到了您的编辑,但不确定这是否会排除您想要包含的内容,但我试过了,它对我有用。

          #!/usr/bin/perl
          
          use strict;
          use warnings;
          
          my @words = qw(bodipr2__ds_di_uat
          bodipr2__ds_dw_uat
          bodipr2__ds_iq_uat
          bodipr2__ds_iq_uat_back
          bodipr2__ds_itsys_uat
          bodipr2__ds_ppp_uat
          bodipr2__ds_psd_uat
          bodipr2__ds_usage_uat
          bodits2__ds_pef_tst
          bodits2__ds_ppp_tst
          bodits2__ds_pri_tst);
          
          print "Original data\n\n";
          
          foreach my $print (@words)
          {
              print "$print\n";
          }
          
          print "\nNew data\n\n";
          
          foreach my $word (@words)
          {
              next if $word =~ /bodi[a-z]+\d__[a-z]+_iq_[a-z]+/;
              print "$word\n";
          }
          

          【讨论】: