공백 일치 정규식-Java


106

정규식 용 Java API는 \s공백과 일치 하는 상태입니다 . 따라서 정규식 \\s\\s은 두 개의 공백과 일치해야합니다.

Pattern whitespace = Pattern.compile("\\s\\s");
matcher = whitespace.matcher(modLine);
while (matcher.find()) matcher.replaceAll(" ");

이것의 목적은 두 개의 연속 된 공백의 모든 인스턴스를 단일 공백으로 바꾸는 것입니다. 그러나 이것은 실제로 작동하지 않습니다.

정규식이나 "공백"이라는 용어에 대해 심각한 오해가 있습니까?


1
String에는 몇 줄의 코드를 절약 할 수있는 replaceAll 함수가 있습니다. download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html
Zach L

1
그것은 당신의 오해가 아니라 자바입니다. "abc \xA0 def \x85 xyz"내가 의미하는 바를 확인하기 위해 문자열을 분할 해보십시오 . 필드가 세 개뿐입니다.
tchrist 2011-04-11

3
"\\ s +"를 사용해 보셨습니까? 이것으로 두 개 이상의 공백을 하나로 바꿉니다.
hrzafer 2013

왜 내 \\ s 분할이 공백으로 분할되지 않는지 한 시간 이상 궁금해했습니다. 정말 감사합니다!
Marcin 2014 년

답변:


44

예, 다음 결과를 가져와야합니다 matcher.replaceAll().

String result = matcher.replaceAll(" ");
System.out.println(result);

18
아. 나는 지구상에서 가장 큰 바보처럼 느껴집니다. 나도 다른 두 사람도 그것을 알아 차리지 못한 것 같았다. 가장 어리석은 사소한 오류가 가끔 우리를 쫓아내는 것 같아요, 응?

사실입니다! 나는 그들의 가장으로 발생하는 추측
saibharath

텍스트에 공백이 있으면 어떻게해야하나요?
Gilberto Ibarra

아래 내 대답에 따라 유니 코드 공백을 일치 시키려면 \ s 대신 \ p {Zs}를 사용하십시오.
로버트

194

UTS # 18의 RL1.2\s 를 충족하기 위해 반드시 필요한 경우에도 Java에서 고유 문자 집합의 공백을 일치시키기 위해 Java를 사용할 수 없습니다. Java는 유니 코드 공백 속성을 지원하지 않기 때문입니다 . 안타깝게도 표준을 준수하지 않습니다.

유니 코드는 26 개의 코드 포인트를 \p{White_Space}다음 과 같이 정의합니다 . 그 중 20 개는 다양한 종류의 \pZ GeneralCategory = Separator 이고 나머지 6 개는 \p{Cc} GeneralCategory = Control 입니다.

공백은 매우 안정적인 속성이며 동일한 속성은 거의 영원히 존재했습니다. 그럼에도 불구하고 Java에는 이들에 대한 유니 코드 표준을 준수하는 속성이 없으므로 대신 다음과 같은 코드를 사용해야합니다.

String whitespace_chars =  ""       /* dummy empty string for homogeneity */
                        + "\\u0009" // CHARACTER TABULATION
                        + "\\u000A" // LINE FEED (LF)
                        + "\\u000B" // LINE TABULATION
                        + "\\u000C" // FORM FEED (FF)
                        + "\\u000D" // CARRIAGE RETURN (CR)
                        + "\\u0020" // SPACE
                        + "\\u0085" // NEXT LINE (NEL) 
                        + "\\u00A0" // NO-BREAK SPACE
                        + "\\u1680" // OGHAM SPACE MARK
                        + "\\u180E" // MONGOLIAN VOWEL SEPARATOR
                        + "\\u2000" // EN QUAD 
                        + "\\u2001" // EM QUAD 
                        + "\\u2002" // EN SPACE
                        + "\\u2003" // EM SPACE
                        + "\\u2004" // THREE-PER-EM SPACE
                        + "\\u2005" // FOUR-PER-EM SPACE
                        + "\\u2006" // SIX-PER-EM SPACE
                        + "\\u2007" // FIGURE SPACE
                        + "\\u2008" // PUNCTUATION SPACE
                        + "\\u2009" // THIN SPACE
                        + "\\u200A" // HAIR SPACE
                        + "\\u2028" // LINE SEPARATOR
                        + "\\u2029" // PARAGRAPH SEPARATOR
                        + "\\u202F" // NARROW NO-BREAK SPACE
                        + "\\u205F" // MEDIUM MATHEMATICAL SPACE
                        + "\\u3000" // IDEOGRAPHIC SPACE
                        ;        
/* A \s that actually works for Java’s native character set: Unicode */
String     whitespace_charclass = "["  + whitespace_chars + "]";    
/* A \S that actually works for  Java’s native character set: Unicode */
String not_whitespace_charclass = "[^" + whitespace_chars + "]";

이제 사용할 수 있습니다 whitespace_charclass + "+"당신의 패턴으로 replaceAll.


모든 것에 대해 죄송합니다. Java의 정규식은 고유 한 고유 문자 집합에서 잘 작동하지 않으므로 실제로 작동하도록하려면 이국적인 후프를 거쳐야합니다.

당신이 공백이 나쁜 생각한다면, 당신은 당신이 얻을 무엇을해야 볼 수 \w\b마지막으로 제대로 작동하도록!

예, 가능합니다. 그리고 예, 그것은 엉망진창입니다. 그것은 자선 활동입니다. 표준을 준수하는 Java 용 정규식 라이브러리를 얻는 가장 쉬운 방법은 ICU에 JNI를 사용하는 것입니다. OraSun은 측정하지 않기 때문에 Google이 Android에서하는 일입니다.

그렇게하고 싶지 않지만 여전히 Java를 고수하고 싶다면, 최소한 UTSRL1.2a 요구 사항을 준수하기 위해 Java의 패턴을 "수정"하는 프런트 엔드 정규식 재 작성 라이브러리가 있습니다. # 18, 유니 코드 정규식 .


12
Java의 정규식 제한에 대해 고맙습니다. +1
ridgerunner 2011

4
나는이 답변을 도움이되었다고 투표하러 갔고 이미 가지고 있다는 것을 알았습니다. 그래서 당신에게 감사 번째 : 시간
앤드류 Wyld

5
이것은 정말 오래되었습니다. 이것이 UNICODE_CHARACTER_CLASS 플래그로 java7에서 수정 된 것이 맞습니까? (? 또는 (U)를 사용)
kritzikratzi

5
@tchrist 이것이 Java 7+에서 수정되면 지금 올바른 방법으로 답변을 업데이트 할 수 있습니까?
beerbajay 2015

7
Java 7 이상에서는 "(? U) \ s"를 사용하여 유니 코드 기술 표준 준수로 정규 표현식을 실행할 수 있습니다. 또는 패턴을 만들 때 UNICODE_CHARACTER_CLASS 플래그를 true로 만들 수 있습니다. 문서는 다음과 같습니다. docs.oracle.com/javase/7/docs/api/java/util/regex/…
Didier A.

15

Java의 경우 (php가 아니라 javascript가 아니라 기타) :

txt.replaceAll("\\p{javaSpaceChar}{2,}"," ")

문자열은 불변이므로 결과를 'txt = txt.replaceAll ()'과 같은 것에 할당해야합니다. 저는 귀하의 답변에 투표하지 않았지만 다른 사람이 그렇게 한 이유 일 수 있습니다.
Enwired

6
나는 완전히 대체가 중요한 것은 4 자바없는 프로그래머가 \\ P {javaSpaceChar} 인 문자열 반환 알
surfealokesea

2
원래 질문은 새 문자열을 변수에 할당하지 않는 실수를 저질렀습니다. 따라서 실수를 지적하는 것이 답의 가장 중요한 포인트입니다.
Enwired

이것은 Groovy에서 내 문제를 완전히 해결했습니다! 드디어! NON-BREAK-SPACE (ASCII 160)를 포함하여 모든 공백과 일치하는 모든 정규식을 시도했습니다 !!!
Piko

5

Regexbuddy (정규식 개발자 응용 프로그램) 포럼에 질문을 보냈을 때 \ s Java 질문에 대해 더 정확한 답변을 받았습니다.

"메시지 작성자 : Jan Goyvaerts

Java에서 \ s, \ d 및 \ w는 ASCII 문자 만 포함합니다. ... 이것은 Java의 버그가 아니라 정규 표현식으로 작업 할 때 알아야 할 많은 것 중 하나입니다. 모든 유니 코드 공백과 줄 바꿈을 일치 시키려면 Java에서 [\ s \ p {Z}]를 사용할 수 있습니다. RegexBuddy는 아직 \ p {javaSpaceChar} ([\ s \ p {Z}]와 정확히 동일한 문자와 일치)와 같은 Java 관련 속성을 지원하지 않습니다.

... \ s \ s는 입력이 ASCII 전용 인 경우 두 개의 공백과 일치합니다. 진짜 문제는 그 질문에 받아 들여진 대답이 지적한 것처럼 OP의 코드에 있습니다. "


3
[\s\p{z}]유니 코드 "다음 줄"문자 U + 0085를 생략합니다. 사용 [\s\u0085\p{Z}].
Robert Tupelo-Schneck 2015 년

3

나를 위해 일하는 것 같습니다.

String s = "  a   b      c";
System.out.println("\""  + s.replaceAll("\\s\\s", " ") + "\"");

인쇄됩니다 :

" a  b   c"

코드 대신 이것을 의도했다고 생각합니다.

Pattern whitespace = Pattern.compile("\\s\\s");
Matcher matcher = whitespace.matcher(s);
String result = "";
if (matcher.find()) {
    result = matcher.replaceAll(" ");
}

System.out.println(result);

3

목적을 위해 다음 스 니펫을 사용할 수 있습니다.

import org.apache.commons.lang3.StringUtils;

StringUtils.normalizeSpace(string);

이렇게하면 간격이 단일로 정규화되고 시작 및 후행 공백도 제거됩니다.

String sampleString = "Hello    world!";
sampleString.replaceAll("\\s{2}", " "); // replaces exactly two consecutive spaces
sampleString.replaceAll("\\s{2,}", " "); // replaces two or more consecutive white spaces

1
Pattern whitespace = Pattern.compile("\\s\\s");
matcher = whitespace.matcher(modLine);

boolean flag = true;
while(flag)
{
 //Update your original search text with the result of the replace
 modLine = matcher.replaceAll(" ");
 //reset matcher to look at this "new" text
 matcher = whitespace.matcher(modLine);
 //search again ... and if no match , set flag to false to exit, else run again
 if(!matcher.find())
 {
 flag = false;
 }
}

3
Mike, 시간을내어 답변 해 주셔서 감사하지만이 질문은 몇 달 전에 해결되었습니다. 이처럼 오래된 질문에 답할 필요가 없습니다.

6
누군가가 다른 더 나은 해결책을 보여줄 수 있다면 오래된 질문에 답하는 것은 완벽하게 합법적입니다.
james.garriss 2015-04-27

1

Java는이 문제가 처음 제기 된 이후로 발전했습니다. \p{Zs}그룹 을 사용하여 모든 방식의 유니 코드 공백 문자를 일치시킬 수 있습니다 .

따라서 하나 이상의 이국적인 공간을 일반 공간으로 바꾸려면 다음과 같이 할 수 있습니다.

String txt = "whatever my string is";
txt.replaceAll("\\p{Zs}+", " ")

당신이 사용한 경우에도 아는 가치, trim()문자열 함수를 당신은 (비교적 새로운)에 대해 살펴해야 strip(), stripLeading()stripTrailing()문자열에 기능을. 모든 종류의 불규칙한 공백 문자를 제거하는 데 도움이 될 수 있습니다. 포함 된 공간에 대한 자세한 정보는 Java의 Character.isWhitespace()기능을 참조하십시오 .


-3

RE에서 공백을 사용하는 것은 고통 스럽지만 작동한다고 생각합니다. OP의 문제는 StringTokenizer 또는 split () 메서드를 사용하여 해결할 수도 있습니다. 그러나 RE를 사용하려면 (println () 주석 처리를 제거하여 matcher가 문자열을 어떻게 분리하는지 확인) 다음은 샘플 코드입니다.

import java.util.regex.*;

public class Two21WS {
    private String  str = "";
    private Pattern pattern = Pattern.compile ("\\s{2,}");  // multiple spaces

    public Two21WS (String s) {
            StringBuffer sb = new StringBuffer();
            Matcher matcher = pattern.matcher (s);
            int startNext = 0;
            while (matcher.find (startNext)) {
                    if (startNext == 0)
                            sb.append (s.substring (0, matcher.start()));
                    else
                            sb.append (s.substring (startNext, matcher.start()));
                    sb.append (" ");
                    startNext = matcher.end();
                    //System.out.println ("Start, end = " + matcher.start()+", "+matcher.end() +
                    //                      ", sb: \"" + sb.toString() + "\"");
            }
            sb.append (s.substring (startNext));
            str = sb.toString();
    }

    public String toString () {
            return str;
    }

    public static void main (String[] args) {
            String tester = " a    b      cdef     gh  ij   kl";
            System.out.println ("Initial: \"" + tester + "\"");
            System.out.println ("Two21WS: \"" + new Two21WS(tester) + "\"");
}}

다음을 생성합니다 (javac로 컴파일하고 명령 프롬프트에서 실행).

% java Two21WS 초기 : "ab cdef gh ij kl"Two21WS : "ab cdef gh ij kl"


8
WTF !? replaceAll()대신 전화 할 수 있는데 왜 그렇게하고 싶 습니까?
Alan Moore
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.