Java에서 대소 문자를 구분하지 않는 리터럴 하위 문자열을 바꾸는 방법


130

replace(CharSequence target, CharSequence replacement)String 의 메소드 를 사용하여 대상을 대소 문자를 구분하지 않게하려면 어떻게해야합니까?

예를 들어, 현재 작동 방식 :

String target = "FooBar";
target.replace("Foo", "") // would return "Bar"

String target = "fooBar";
target.replace("Foo", "") // would return "fooBar"

두 예제가 모두 "Bar"를 반환하도록 대 / 소문자를 구분하지 않도록 바꾸려면 어떻게해야합니까 (또는 더 적합한 방법이있는 경우)?

답변:


284
String target = "FOOBar";
target = target.replaceAll("(?i)foo", "");
System.out.println(target);

산출:

Bar

그 언급이의 가치가 replaceAll취급 예기치 않은 결과가 발생할 수 있습니다 정규식 패턴으로 첫 번째 인수를. 이 문제를 해결하려면 Pattern.quote주석에서 제안한대로 사용 하십시오.


1
대상에 $와 같은 발음 구별 부호가 포함되어 있으면 어떻게 되나요?
stracktracer

3
두 가지 의미 : 1. "blÁÜ123".replaceAll ( "(? i) bláü")는 아무것도 대체하지 않습니다. 2. "Sentence! End".replaceAll ( "(? i) Sentence.")가 예상보다 많이 대체 될 수 있습니다.
stracktracer

1
문자열을 너무 간단하게 일치시키는 정규식으로 바꿀 수 없습니다. 일반적으로 정확하지 않으며 특정 경우에만 작동합니다.
Danubian Sailor

19
검색 문자열이 정규식으로 해석되지 않도록하려면 Pattern.quote ()를 사용하십시오. 이 doe는 위에 나열된 유니 코드 문제를 해결하지 못하지만 기본 문자 집합에는 적합합니다. 예 target.replaceAll("(?i)"+Pattern.quote("foo"), "");
Jeff Adamson 2016 년

1
그냥 확인하십시오. 문자열이 "foo"인 경우 Pattern.quote ( "foo")가 필요하지 않습니까? 더 멋진 것만 맞습니까?
ed22

10

대소 문자를 신경 쓰지 않으면 모든 대문자를 반환하는지 여부는 중요하지 않습니다.

target.toUpperCase().replace("FOO", "");

á와 같은 문자를 다루는 경우 로케일을 toUpperCase (locale)로 전달할 수도 있습니다.
rob

10

아마도 다른 접근 방식만큼 우아하지는 않지만 매우 견고하고 따르기 쉽습니다. Java를 처음 사용하는 사람들을 위해. String 클래스에 대해 한 가지 사실은 다음과 같습니다. 매우 오랫동안 주변에 있었고 regexp로 전역 대체와 String으로 전역 대체를 지원하는 동안 (CharSequences를 통해) 마지막으로 간단한 부울 매개 변수가 없습니다. : 'isCaseInsensitive'. 실제로, 하나의 작은 스위치를 추가하면 초보자에게 발생하는 모든 문제를 피할 수 있다고 생각했습니다. 이제 JDK 7에서 String은 여전히이 작은 추가 기능을 지원하지 않습니다!

어쨌든, 나는 그립을 멈출 것이다. 특히 Java를 처음 접하는 모든 사람들을 위해 여기 잘라낸 붙여 넣기 deus ex machina가 있습니다. 내가 말했듯이, 우아하지 않고 매끄러운 코딩 상을 수상하지는 않지만 작동하고 신뢰할 수 있습니다. 의견이 있으시면 언제든지 기부하십시오. (예, StringBuffer는 아마도 두 개의 문자열 변이 줄을 관리하는 더 나은 선택이지만 기술을 쉽게 바꿀 수 있습니다.)

public String replaceAll(String findtxt, String replacetxt, String str, 
        boolean isCaseInsensitive) {
    if (str == null) {
        return null;
    }
    if (findtxt == null || findtxt.length() == 0) {
        return str;
    }
    if (findtxt.length() > str.length()) {
        return str;
    }
    int counter = 0;
    String thesubstr = "";
    while ((counter < str.length()) 
            && (str.substring(counter).length() >= findtxt.length())) {
        thesubstr = str.substring(counter, counter + findtxt.length());
        if (isCaseInsensitive) {
            if (thesubstr.equalsIgnoreCase(findtxt)) {
                str = str.substring(0, counter) + replacetxt 
                    + str.substring(counter + findtxt.length());
                // Failing to increment counter by replacetxt.length() leaves you open
                // to an infinite-replacement loop scenario: Go to replace "a" with "aa" but
                // increment counter by only 1 and you'll be replacing 'a's forever.
                counter += replacetxt.length();
            } else {
                counter++; // No match so move on to the next character from
                           // which to check for a findtxt string match.
            }
        } else {
            if (thesubstr.equals(findtxt)) {
                str = str.substring(0, counter) + replacetxt 
                    + str.substring(counter + findtxt.length());
                counter += replacetxt.length();
            } else {
                counter++;
            }
        }
    }
    return str;
}

복잡성은 O (size_str가 size_findtext *)와 같이이 방법은 느린 완전히 인
믈라덴 Adamovic

9

정규식은 일부 문자가 예약되어 있기 때문에 관리하기가 매우 복잡합니다. 예를 들어 "foo.bar".replaceAll(".")점은 "anything"을 의미하기 때문에 빈 문자열을 생성합니다. 교체하려는 경우 점만 매개 변수로 표시해야합니다 "\\.".

더 간단한 해결책은 StringBuilder 객체를 사용하여 텍스트를 검색하고 바꾸는 것입니다. 두 가지가 필요합니다. 하나는 소문자 버전의 텍스트를 포함하고 다른 하나는 원래 버전을 포함합니다. 검색은 소문자로 수행되며 감지 된 색인은 원래 텍스트를 대체합니다.

public class LowerCaseReplace 
{
    public static String replace(String source, String target, String replacement)
    {
        StringBuilder sbSource = new StringBuilder(source);
        StringBuilder sbSourceLower = new StringBuilder(source.toLowerCase());
        String searchString = target.toLowerCase();

        int idx = 0;
        while((idx = sbSourceLower.indexOf(searchString, idx)) != -1) {
            sbSource.replace(idx, idx + searchString.length(), replacement);
            sbSourceLower.replace(idx, idx + searchString.length(), replacement);
            idx+= replacement.length();
        }
        sbSourceLower.setLength(0);
        sbSourceLower.trimToSize();
        sbSourceLower = null;

        return sbSource.toString();
    }


    public static void main(String[] args)
    {
        System.out.println(replace("xXXxyyyXxxuuuuoooo", "xx", "**"));
        System.out.println(replace("FOoBaR", "bar", "*"));
    }
}

1
잘 작동합니다! "target"은 null이 아니어야합니다. sbSourceLower를 지울 필요가 없습니다 (더 이상).
msteiger

간결한 솔루션 및 @msteiger에 감사드립니다. 구아바, 아파치 커먼즈 등과 같은 유명한 라이브러리에 왜 비슷한 솔루션을 추가하지 않았는지 궁금합니다.
yetanothercoder

4

비 유니 코드 문자의 경우 :

String result = Pattern.compile("(?i)препарат", 
Pattern.UNICODE_CASE).matcher(source).replaceAll("БАД");

4

org.apache.commons.lang3.StringUtils :

공개 정적 문자열 replaceIgnoreCase (문자열 텍스트, 문자열 검색 문자열, 문자열 대체)

대소 문자를 구분하지 않으면 다른 문자열 내에서 모든 문자열이 대체됩니다.


3

나는 정규식으로 사용 하는 smas대답 을 좋아 replaceAll합니다. 동일한 대체를 여러 번 수행하려는 경우 정규식을 한 번 사전 컴파일하는 것이 좋습니다.

import java.util.regex.Pattern;

public class Test { 

    private static final Pattern fooPattern = Pattern.compile("(?i)foo");

    private static removeFoo(s){
        if (s != null) s = fooPattern.matcher(s).replaceAll("");
        return s;
    }

    public static void main(String[] args) {
        System.out.println(removeFoo("FOOBar"));
    }
}

3

타사 라이브러리없이 간단하게 만드십시오.

    final String source = "FooBar";
    final String target = "Foo";
    final String replacement = "";
    final String result = Pattern.compile(target, Pattern.LITERAL | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE).matcher(source)
.replaceAll(Matcher.quoteReplacement(replacement));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.