代码之家  ›  专栏  ›  技术社区  ›  Don Wakefield

如何找到混合了Perl大小写的字符串?

  •  2
  • Don Wakefield  · 技术社区  · 15 年前

    我正在尝试过滤数千个文件,寻找那些包含混合大小写的字符串常量的文件。这样的字符串可以嵌入空白,但不能包含空白本身。因此以下(包含UC字符)是匹配的:

    "  AString "   // leading and trailing spaces together allowed
    "AString "     // trailing spaces allowed
    "  AString"    // leading spaces allowed
    "newString03"  // numeric chars allowed
    "!stringBIG?"  // non-alphanumeric chars allowed
    "R"            // Single UC is a match
    

    但这些不是:

    "A String" // not a match because it contains an embedded space
    "Foo bar baz" // does not match due to multiple whitespace interruptions
    "a_string" // not a match because there are no UC chars
    

    我仍然想匹配包含 二者都 模式:

    "ABigString", "a sentence fragment" // need to catch so I find the first case...
    

    我想使用perl regexps,最好由 ack 命令行工具。显然, \w \ W 不会工作的。似乎 \ S 应与非空格字符匹配。我似乎不知道如何嵌入“每个字符串至少一个大写字符”的要求…

    ack --match '\"\s*\S+\s*\"'
    

    是我最近得到的。我需要更换 s+ 具有 某物 它捕获“至少一个大写(ASCII)字符(在非空白字符串的任何位置)”要求。

    这在C/C++中是很简单的程序(是的,Perl,在程序上,不诉诸ReExcel),我只是想知道是否有一个正则表达式可以做同样的工作。

    2 回复  |  直到 15 年前
        1
  •  7
  •   Community THelper    7 年前

    以下模式通过了所有测试:

    qr/
      "      # leading single quote
    
      (?!    # filter out strings with internal spaces
         [^"]*   # zero or more non-quotes
         [^"\s]  # neither a quote nor whitespace
         \s+     # internal whitespace
         [^"\s]  # another non-quote, non-whitespace character
      )
    
      [^"]*  # zero or more non-quote characters
      [A-Z]  # at least one uppercase letter
      [^"]*  # followed by zero or more non-quotes
      "      # and finally the trailing quote
    /x
    

    使用使用上述模式的测试程序 /x 因此,没有空格和注释作为输入 ack-grep (AS) ack 在Ubuntu上调用)

    #! /usr/bin/perl
    
    my @tests = (
      [ q<"  AString ">   => 1 ],
      [ q<"AString ">     => 1 ],
      [ q<"  AString">    => 1 ],
      [ q<"newString03">  => 1 ],
      [ q<"!stringBIG?">  => 1 ],
      [ q<"R">            => 1 ],
      [ q<"A String">     => 0 ],
      [ q<"a_string">     => 0 ],
      [ q<"ABigString", "a sentence fragment"> => 1 ],
      [ q<"  a String  "> => 0 ],
      [ q<"Foo bar baz">  => 0 ],
    );
    
    my $pattern = qr/"(?![^"]*[^"\s]\s+[^"\s])[^"]*[A-Z][^"]*"/;
    for (@tests) {
      my($str,$expectMatch) = @$_;
      my $matched = $str =~ /$pattern/;
      print +($matched xor $expectMatch) ? "FAIL" : "PASS",
            ": $str\n";
    }
    

    生成以下输出:

    $ ack-grep '"(?![^"]*[^"\s]\s+[^"\s])[^"]*[A-Z][^"]*"' try
      [ q<"  AString ">   => 1 ],
      [ q<"AString ">     => 1 ],
      [ q<"  AString">    => 1 ],
      [ q<"newString03">  => 1 ],
      [ q<"!stringBIG?">  => 1 ],
      [ q<"R">            => 1 ],
      [ q<"ABigString", "a sentence fragment"> => 1 ],
    my $pattern = qr/"(?![^"]*[^"\s]\s+[^"\s])[^"]*[A-Z][^"]*"/;
      print +($matched xor $expectMatch) ? "FAIL" : "PASS",
    

    对于C壳和导数,你必须逃离爆炸:

    % ack-grep '"(?\![^"]*[^"\s]\s+[^"\s])[^"]*[A-Z][^"]*"' ...
    

    我希望我能保留突出显示的匹配项,但这似乎不是 allowed .

    注意转义双引号( \" )会严重混淆这种模式。

        2
  •  0
  •   Andomar    15 年前

    您可以使用字符类添加需求,例如:

    ack --match "\"\s*\S+[A-Z]\S+\s*\""
    

    我想是的 ack 一次匹配一行。这个 \S+\s*\" 部件可以匹配一行中的多个右引号。它将与 "alfa"" 而不是仅仅 "alfa" .