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("");

これにより、1 つの問題が解決され、現在は 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両方のキャプチャとなります。OtoLowerCase()

ループはreplaceAll()ではなく によって実行されていfind()ます。が呼び出される前にキャプチャMatcher#find()を返すように、グループを初期化する必要があります。group(1)replaceAll()

ただし、これはキャプチャが同じままであることを意味します。これは要件を十分に満たしますが、 BOobbOobboObbOoObbooOoOoOoOoOObのような文字列に対してマッチャーをリセットする必要があります(2 つの 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 をマッピングしますが、私が望むように動作することに非常に近いと思います。ボブにマッピングされていないため、これを使用している理由に影響を与えるとは思えません。

ところで、誰かがこれを最適化する方法を理解できる場合は、お気軽にコメントしてください! 必要かどうかはわかりませんが、.reset()が少し気になります。

于 2013-07-28T07:45:13.377 に答える