在字符串中查找特定字符出现次数是否为奇数的正则表达式

6
有没有办法在Java中写一个正则表达式,用于查找一个字符串中特定字符(比如 "a")的数量是否为奇数?我已经使用了更冗长的代码来实现此功能,主要使用了以下方法:
public static boolean hasEvenNumber(String s) {
        int count = 0;

        Pattern p = Pattern.compile("(^a)*(a)");
        Matcher m = p.matcher(s);
        while (m.find())
            count++;

        if (count % 2 != 0)
            return true;
        return false;
    }

如果以字符串"jsadaajaaikadjasl"作为参数传递,则返回true,因为它包含7个"a"。是否有一种更优雅的方法只使用正则表达式并像下面这样检查呢?
Pattern p = Pattern.compile(...);
Matcher m = p.matcher(s);
if(m.matches())
   return true;  

?


为什么需要正则表达式?一个简单的循环就可以做到。 - anubhava
!s.replaceAll("[^*a[^a]a[^a]*|[^a]+", "").isEmpty(); - Joop Eggen
我知道限制解决方案的方式并不是最好的选择,但正因为如此,我才在询问。我知道有很多种方法可以做到这一点,但我只对使用正则表达式的方式感兴趣。 - arjacsoh
这里没有理由使用正则表达式。 - ealfonso
我不明白为什么正则表达式的解决方案可以比循环解决方案更简洁,而且它会更加晦涩难懂——在这里使用正则表达式就是纯粹的恶意。Java代码的关键部分将是for(int i=0;i<s.length();i++) if(s.charAt(i)=='a')n++; 这里给出的大多数表达式本身几乎和这个一样长! - Bill K
8个回答

5

只需创建与偶数匹配的模式,如"(?:[^a]*a[^a]*a)*",然后再添加一个出现次数,(?:[^a]*a[^a]*a)*[^a]*a[^a]。现在,如果matcher.matches返回true,则表示您有奇数个出现次数。


你需要为正则表达式添加锚点以测试整个字符串 :) 否则,使用.matches - Jerry
我说“使用matches”。但我忘记了重复。已修复。 - Holger

3
我不知道为什么你想在这里使用正则表达式(我也不确定我是否想知道),但你可以尝试使用[^a]*a([^a]*a[^a]*a)*[^a]*
它的意思是:
[^a]*            # zero or more non-a characters 
                 # (in case string starts with non-a character)
a                # one "a" character 
([^a]*a[^a]*a)*  # two "a" characters preceded by zero or more non-a characters
                 # (this will match any numbers of "..a..a" "pairs")
[^a]*            # zero or more non-a characters 
                 # (in case string ends with non-a character)

如果您想匹配偶数个 a,只需从正则表达式的开头或中删除[^a]*a
System.out.println("jsadaajaaikadjasl".matches("[^a]*a([^a]*a[^a]*a)*+[^a]*"));
System.out.println("jasadaajaaikadjasl".matches("[^a]*a([^a]*a[^a]*a)*+[^a]*"));

输出:

true
false

不必使用正则表达式,可以使用这个简单的方法,该方法将遍历所有字符串字符,并将其与搜索对象进行比较,每当它找到匹配项时,就会将boolean标记从odd翻转为even或反之亦然。

public static boolean hasOdd(String s, char character) {
    boolean response = false;
    for (char c : s.toCharArray())
        if (c == character)
            response = !response;
    return response;
}

//...

System.out.println(hasOdd("jsadaajaaikadjasl", 'a'));//true
System.out.println(hasOdd("jasadaajaaikadjasl", 'a'));//false

1

我只会计算字符数并检查字符串是否以特定字符开头。你可以使用Apache Commons的CharsetUtils来实现:

public static boolean hasOddNumber(String s, char c) {
  boolean hasOddNumber = false; 
  if (s.charAt(0) != c){
    hasOddNumber = CharSetUtils.count(s, c) % 2 != 0;
  }
  return hasOddNumber;      

此外,我会将方法名更改为hasOddNumber,因为您的问题暗示您想知道一个字符串是否具有奇数次出现。

0
如果你真的需要一个正则表达式,那么这段代码应该可以工作:
String str = "abadaa";
boolean isAOdd = str.matches("^[^a]*a(?=(([^a]*a){2})*[^a]*$).*$"); // false

str = "abadaacad";
isAOdd = str.matches("^[^a]*a(?=(([^a]*a){2})*[^a]*$).*$"); // true

0
(?:([^a]*a[^a]*a[^a]*)*)

匹配偶数个a

[^a]*a(?:([^a]*a[^a]*a[^a]*)*)

匹配奇数个 a


0

这里应该有一个能够实现你所尝试达成目标的工作示例。

public static boolean hasEvenNumber(String s) {
    int counter = 0;
    Pattern p = Pattern.compile("([aA])?{1,}");
    Matcher m = p.matcher(s);
    while (m.find()) {
        if (m.group().equalsIgnoreCase("a"))
            counter++;
    }
    return (counter != 0 && counter%2==0);
}

结果对于 "aba""abaa" 是相同的。 - Pshemo
非常正确。模式 p = Pattern.compile("([aA])?{1,}"); 应该可以解决这个问题。 - AppX
这将包括任何字符的出现。"1" -> true,"12"->false。 - Pshemo
好的。让我们为组中的a添加检查吧。更新的示例。 - AppX
它能工作,但只是因为你正在检查先前创建的混乱的每个结果。你的正则表达式只是找到空字符串(对于非“a”字符)或“a”。因此,你的正则表达式没有帮助,只是让一切变得更加复杂。更容易的方法是迭代每个字符(例如使用string.charAt(i)),并将其与“a”进行比较。 - Pshemo

0
public static void main(String[] args) {

    String s = "jsadaajaaikadjasl";
    System.out.println(hasEvenNumber(s,"a"));
}

public static boolean hasEvenNumber(String s, String letter) {

    int count = s.length() - s.replaceAll(letter, "").length();
    return count % 2 == 0 ? false : true ;
}

0

奇数: "^[^a]*(a[^a]*a[^a]*)*a[^a]*$"

偶数: "^([^a]*a[^a]*a[^a]*)+$"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接