【问题标题】:How do I count odd and even amounts of characters with regular expressions?如何使用正则表达式计算奇数和偶数字符?
【发布时间】:2011-06-12 19:19:20
【问题描述】:

我正在尝试提取所有具有偶数个 B 和奇数个 C 的字符串。我有正则表达式来匹配奇数 A 甚至 B,但我无法让两者一起工作。字符串由空格(制表符、换行符、空格)分隔。

例如

XABBAC     ABCDEBCC ABSDERERES ABBAAJSER     HGABAA

我有奇数的 A

\b[^A]*A([^A]*A[^A]*A)*[^A]*\b

甚至是 B 的

\b[^B]*(B[^B]*B[^B]*)*[^B]*\b

我知道我需要使用 +ve lookahead 并尝试过:

\b(?=[^A]*A([^A]*A[^A]*A)*[^A]*\b)[^B]*(B[^B]*B[^B]*)*[^B]*\b

但它不起作用 - 有人知道为什么吗?

【问题讨论】:

  • 似乎工作in ruby。您能否举一个不适合您的示例,并提供您的 Java 代码?
  • @marcog 哈哈。在红宝石中,这将是一个简单的单行。 data.split.select{|x| x.count("B").even? && x.count("C").odd?} 结果:["XABBAC", "ABCDEBCC"]
  • “问题”?严重地?这就是你标记这个?与所有其他不涉及某种问题的问题相反?...重新标记...

标签: regex


【解决方案1】:

使用 commons.lang.StringUtils 更加简洁:

String data = "XABBAC     ABCDEBCC ABSDERERES ABBAAJSER    HGABAA";
String[] items = data.split("\\s+");

for(String item: items ) {
    if (countMatches(item, "B") % 2 == 0
     && countMatches(item, "C") % 2 != 0) {
        System.out.println( item );
    }
}

【讨论】:

    【解决方案2】:

    正则表达式被高估了

        String str = "XABBAC     ABCDEBCC ABSDERERES ABBAAJSER     HGABAA";
        String[] s = str.split("\\s+");
        for (int j=0 ;j< s.length;j++) {
            int countC=0  ;
            int countB=0;
            for(int i=0;i<s[j].length();i++){
                char c = s[j].charAt(i) ;
                if (c == 'C') countC++;
                if (c == 'B') countB++;
            }
            if ( (countC % 2) != 0 )
                System.out.println( s[j] + " has odd C");
            if ( (countB % 2) == 0 )
                System.out.println( s[j] + " has even B");
        }
    

    【讨论】:

      【解决方案3】:

      正如 Anon 已经提到的:您的模式匹配空字符串,导致 m.find() 永远不会在目标字符串中前进。因此,您需要让您的偶数 B 实际匹配包含 2、4、6、...数量的 B 的字符串。如果需要,您可以在偶数个 B 和以下代码之间交替:[^B\\s]+(匹配包含 0 个 B 的字符串)。只要你真正匹配一个或多个字符,那么你应该没问题。

      此外,您不希望向前看并让否定类匹配空格:那样会得到太多匹配。

      试试这样的:

      String text = "XABBAC     ABCDEBCC ABSDERERES ABBAAJSER     HGABAA";
      
      String oddAs = "\\b[^A\\s]*A([^A\\s]*A[^A\\s]*A)*[^A\\s]*\\b";
      String evenBs = "\\b([^B\\s]*(B[^B\\s]*B[^B\\s]*)+|[^B\\s]+)\\b";
      
      Pattern p = Pattern.compile(String.format("(?=%s)(?=%s)\\S+", oddAs, evenBs));
      Matcher m = p.matcher(text);
      
      while (m.find()) {
          System.out.println(m.group());
      }
      

      产生:

      ABCDEBCC
      ABBAAJSER
      

      【讨论】:

      • 嗨,你能向我解释一下你在 patter.compile 中传递了什么吗?感谢您的回复。特别是 %s 是什么?
      • @dr85, String.format 返回一个字符串(2 %soddAsevenBs 替换)。这与执行以下操作相同:"(?=" + oddAs + ")(?=" + evenBs + ")\\S+" 并将其提供给静态 Pattern.compile(...) 方法。
      • @dr85,与其想知道我发布的代码 sn-p 做什么和不做什么,为什么不试试呢?它确实匹配ABABABABBA(我刚刚测试过)。
      • 我能问一下你为什么使用两个前瞻吗?
      • 只有一个不可能吗?
      【解决方案4】:

      问题是您的正则表达式(regexen?)可以匹配零个字符 - \b\b 将匹配单个单词边界,\b{someregexthatcanmatchzerocharacters}\b 也将匹配。

      【讨论】:

      • @dr85:是的,确实如此。但是,它不消耗任何字符 - \b\b 将匹配 single 字边界;第一个\b匹配一个边界,然后引擎尝试匹配第二个\b,它仍然在单词边界,所以它匹配。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-11
      • 2015-07-06
      • 1970-01-01
      • 2021-08-06
      • 2021-05-16
      • 2015-09-17
      相关资源
      最近更新 更多