有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

regex如何使用(正则表达式)删除java中的重复字母,并且不区分大小写

我一直在尝试用字母的小写版本(java)替换任何重复的字母。例如:

我想要一个映射以下内容的函数:

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

但是,我使用regexs(在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。(对胸部有效)

我还尝试:

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

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

注意:它还应映射boooooooooooob->;波波波波

我觉得在这一点上,循环字符串并基于每个字符执行一些逻辑可能更容易,但我不想放弃使用regexs。。。如果存在使用regexs的解决方案,那么它是否比遍历每个字符的循环更有效

提前谢谢

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

鲍勃->;鲍勃


共 (2) 个答案

  1. # 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,它会对我使用它的原因产生太大的影响

    顺便说一句,如果有人能看到如何优化这个,请随意评论!这确实让我有点恼火。reset(),但我不确定是否有必要

  2. # 2 楼答案

    在这里使用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()运行,而不是由find()运行^需要{}来初始化组,以便group(1)在调用replaceAll()之前返回捕获

    但是,这也意味着捕获保持不变,这满足了您的要求,但需要为类似于boobboobboobbooboooob的字符串重置匹配器(注意双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()来确定匹配是否在输入的开头,而大小写保持不变