3

我一直在尝试做的是将任何重复的字母替换为其字母的小写版本(在 java 中)。例如:

我想要一个映射的函数:

bob -> bob
bOb -> bob
bOOb -> bob
bOob -> bob
boOb -> bob
bob -> bob
Bob -> Bob
bOb -> bob

但是,我没有成功使用正则表达式(在 Java 中)做到这一点。

我尝试了以下方法:

    String regex = "([A-za-z])\\1+";
    String str ="bOob";
    Pattern pattern = Pattern.compile(regex , Pattern.CASE_INSENSITIVE);
    Matcher matcher = pattern.matcher(str);
    System.out.println(matcher.replaceAll("$1"));

但是,这将返回 bOb 而不是 bob。(它适用于 boOb)。

我也试过:

        Pattern pattern = Pattern.compile("(?i)([A-Za-z0-9])(?=\\1)", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        return matcher.replaceAll("");

这解决了一个问题,现在是 bOob -> bob 但带来了另一个问题,因为现在它将 boOb 映射到 bob。

注意:它还应该映射 BOobOoboObOoObooOoOoOoOoOOb -> Bobobobobob。

我觉得此时循环字符串并根据每个字符执行一些逻辑可能会更容易,但我只是不想放弃使用正则表达式......如果存在使用正则表达式的解决方案,是不是更多可能比遍历每个字符的循环更有效?

提前致谢!

PS:我知道在传递字符串之前可以将所有内容都小写,但这不是我想要的,因为它映射:

鲍勃->鲍勃

4

2 回答 2

3

使用Matcher#group()而不是$1这里

if (matcher.find()) {
    System.out.println(matcher.replaceAll(matcher.group(1)
                                          .toLowerCase()));
}

让你利用toLowerCase()那时。

编辑:(回应OP的评论)

Matcher#group(n)等同于$n-- 它指的是第n 个捕获组。因此,group(1)两者$1都捕获O,只是您可以切换捕获toLowerCase()

循环由replaceAll()not运行find()Matcher#find()需要初始化组,以便在调用group(1)之前返回捕获。replaceAll()

但是,这也意味着捕获保持不变,这足以满足您的要求,但需要为类似BOobbOobboObbOoObbooOoOoOoOoOOb的字符串重置匹配器(注意双 b)。现在必须驱动循环,Mathcer#find()这意味着replaceAll()replaceFirst().

String regex = "([A-Za-z])\\1+";
String str = "BOobbOobboObbOoObbooOoOoOoOoOObb";

Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);

while (matcher.find()) {
    str = matcher.replaceFirst(matcher.start() > 0 ? matcher.group(1)
                                    .toLowerCase() : matcher.group(1));
    matcher.reset(str);
}

System.out.println(str); // Bobobobobob

Matcher#start()在这里用于识别匹配是否在输入的开头,其中大小写保持不变。

于 2013-07-28T04:23:27.500 回答
1

我认为这是我正在寻找的代码(基于接受的答案):

public String removeRepeatedLetters(String str, boolean caseSensitive){
    if(caseSensitive){
        return this.removeRepeatedLetters(str); //uses case sensitive version
    }else{
        Pattern patternRep = Pattern.compile("([A-Za-z])(\\1+)", Pattern.CASE_INSENSITIVE);
        Matcher matcher = patternRep.matcher(str);
        String output = str;
        while(matcher.find()){
            String matchStr = matcher.group(1);
            output = matcher.replaceFirst(matchStr.toLowerCase());
            matcher = patternRep.matcher(output);
            matcher.reset();
        }
        return output;
    }   
}

它所做的是替换任何重复的字母(无论是大写还是非大写)并将它们替换为单个非大写字母。

我认为它非常接近于我想要的工作,尽管它映射 Bbob -> bob。我怀疑因为它没有映射到 Bob,它会影响我使用它的原因。

顺便说一句,如果有人可以看到如何优化它,请随时发表评论!.reset() 确实让我有些恼火,尽管我不确定它是否有必要。

于 2013-07-28T07:45:13.377 回答