Boşluklarla Eşleşen Normal İfade - Java


106

Normal ifadeler için Java API, \sboşluklarla eşleşecek durumlardır . Dolayısıyla normal ifade \\s\\siki boşlukla eşleşmelidir.

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

Bunun amacı, iki ardışık boşluğun tüm örneklerini tek bir boşlukla değiştirmektir. Ancak bu aslında işe yaramıyor.

Normal ifadeler veya "boşluk" terimi hakkında ciddi bir yanlış anlama mı yaşıyorum?


1
String, size birkaç satır kod kaydedecek bir replaceAll işlevine sahiptir. download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html
Zach L

1
Bu senin yanlış anlaman değil, Java'nın. "abc \xA0 def \x85 xyz"Ne demek istediğimi görmek için bir dizeyi bölmeyi deneyin : orada sadece üç alan var.
tchrist

3
"\\ s +" yı denediniz mi? Bununla iki veya daha fazla boşluğu bire değiştirirsiniz.
hrzafer

Bir saatten fazla bir süredir bölümümün neden beyaz alana bölünmediğini merak ediyorum. Milyonlarca kez teşekkürler!
Marcin

Yanıtlar:


44

Evet, sonucunu almalısın matcher.replaceAll():

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

18
Gah. Dünyadaki en büyük aptal gibi hissediyorum. Ne ben ne de diğer iki kişi bunu fark etmiş gibiydi. Sanırım en aptalca küçük hatalar bizi bazen atlatıyor, ha?

Çok doğru! Sanırım bu en
iyileriyle

Metinde Beyaz Boşluklar varsa almam gerekirse ne olur?
Gilberto Ibarra

Aşağıdaki cevabıma göre, unicode boşlukla eşleştirmek istiyorsanız \ s yerine \ p {Zs} kullanın.
Robert

195

\sJava'da beyaz boşluğu kendi yerel karakter kümesiyle eşleştirmek için kullanamazsınız çünkü Java, Unicode beyaz boşluk özelliğini desteklemiyor - bunu yapmak kesinlikle UTS # 18'in RL1.2'sini karşılamak için gerekli olsa da ! Ne yazık ki sahip olduğu şey standartlara uygun değil.

Unicode 26 kod noktasını şu şekilde tanımlar \p{White_Space}: 20 tanesi çeşitli \pZ GeneralCategory = Separator türleri ve geri kalan 6 tanesi \p{Cc} GeneralCategory = Control .

Beyaz boşluk oldukça istikrarlı bir özelliktir ve aynı olanlar neredeyse sonsuza kadar ortalıktadır. Öyle olsa bile, Java'nın bunlar için Unicode Standardına uyan bir özelliği yoktur, bu nedenle bunun yerine aşağıdaki gibi bir kod kullanmanız gerekir:

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 + "]";

Şimdi kullanabilirsiniz whitespace_charclass + "+"Gözlerinde farklı desen olarak replaceAll.


Tüm bunlar için üzgünüm. Java'nın normal ifadeleri kendi yerel karakter setinde pek iyi çalışmıyor ve bu yüzden onları çalıştırmak için gerçekten egzotik çemberlerden geçmeniz gerekiyor.

Ve beyaz boşluğun kötü olduğunu düşünüyorsanız, elde etmek \wve \bsonunda düzgün davranmak için ne yapmanız gerektiğini görmelisiniz !

Evet, mümkün ve evet, kafa karıştırıcı bir karmaşa. Bu hayırseverlik bile. Java için standartları karşılayan bir normal ifade kitaplığı edinmenin en kolay yolu, JNI'ye ICU'nun malzemelerine gitmektir. Google'ın Android için yaptığı şey bu, çünkü OraSun'un ölçüsü yok.

Bunu yapmak istemiyor ama yine de Java'ya bağlı kalmak istiyorsanız, Java'nın kalıplarını en azından UTS'deki RL1.2a gereksinimlerine uydurmak için "düzelttiğini" yazdım. # 18, Unicode Normal İfadeler .


12
Java'nın normal ifade sınırlamaları konusunda bilgi verdiğiniz için teşekkürler. +1
ridgerunner

4
Bu yanıtı faydalı olarak oylamaya gittim ve zaten sahip olduğumu öğrendim. Bu yüzden ikinci kez teşekkür ederim :)
Andrew Wyld

5
bu gerçekten eski. bunun java7'de UNICODE_CHARACTER_CLASS bayrağıyla düzeltildiği doğru mu? (veya (? U) kullanarak)
kritzikratzi

5
@tchrist Bu, java 7+ sürümünde düzeltildiyse, cevabı bunu yapmanın şimdi doğru yolu ile güncelleyebilir misiniz?
beerbajay

7
Java 7+ ile, normal ifadeyi Unicode Teknik Standart uyumluluğuyla çalıştırmak için şunları yapabilirsiniz: "(? U) \ s". Veya kalıbı oluştururken UNICODE_CHARACTER_CLASS bayrağını doğru yapabilirsiniz. İşte belge: docs.oracle.com/javase/7/docs/api/java/util/regex/…
Didier A.

15

Java için (php değil, javascript değil, başka bir şey değil):

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

Dizeler değişmezdir, bu nedenle sonucu 'txt = txt.replaceAll ()' gibi bir şeye atamalısınız, cevabınızı oylamadım, ancak bu yüzden başka biri bunu yaptı.
2013

6
ReplaceAll'ın bir dize döndürdüğünü biliyorum, önemli olan 4 java programcısı \\ p {javaSpaceChar}
surfealokesea

2
Orijinal soru, yeni dizeyi bir değişkene atamama hatasını yaptı. Bu hataya işaret etmek bu nedenle cevabın en önemli noktasıdır.
2013

Bu Groovy'deki sorunumu tamamen çözdü! En sonunda! NON-BREAK-SPACE (ASCII 160) dahil tüm beyaz boşluklarla eşleşen bulabildiğim her regex'i deniyordum !!!
Piko

5

Bir Regexbuddy (regex geliştirici uygulaması) forumuna bir soru gönderdiğimde, Java soruma daha kesin yanıt aldım:

"Mesaj yazarı: Jan Goyvaerts

Java'da \ s, \ d ve \ w kısaltmaları yalnızca ASCII karakterlerini içerir. ... Bu Java'daki bir hata değil, normal ifadelerle çalışırken bilmeniz gereken pek çok şeyden sadece biridir. Tüm Unicode boşluklarını ve satır sonlarını eşleştirmek için Java'da [\ s \ p {Z}] kullanabilirsiniz. RegexBuddy, \ p {javaSpaceChar} ([\ s \ p {Z}] ile tam olarak aynı karakterlerle eşleşen) gibi Java'ya özgü özellikleri henüz desteklememektedir.

... \ s \ s iki boşlukla eşleşir, eğer giriş yalnızca ASCII ise. Asıl sorun, bu soruda kabul edilen yanıtın işaret ettiği gibi OP'nin kodunda. "


3
[\s\p{z}]Unicode "sonraki satır" karakterini U + 0085 atlar. Kullanın [\s\u0085\p{Z}].
Robert Tupelo-Schneck

3

Benim için iş gibi görünüyor:

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

yazdıracak:

" a  b   c"

Kodunuz yerine bunu yapmayı düşündüğünüzü düşünüyorum:

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

System.out.println(result);

3

Amacınız için bu snnippet'i kullanabilirsiniz:

import org.apache.commons.lang3.StringUtils;

StringUtils.normalizeSpace(string);

Bu, aralığı tek olacak şekilde normalleştirecek ve başlangıç ​​ve son beyaz boşlukları da kaldıracaktır.

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, zaman ayırıp cevaplamanı takdir etsem de, bu soru birkaç ay önce çözüldü. Bu kadar eski sorulara cevap vermeye gerek yok.

6
Birisi farklı, daha iyi bir çözüm gösterebilirse, eski soruları yanıtlamak tamamen yasaldır.
james.garriss

1

Java, bu sorun ilk gündeme geldiğinden beri gelişti. \p{Zs}Grubu kullanarak tüm unicode boşluk karakterlerini eşleştirebilirsiniz .

Bu nedenle, bir veya daha fazla egzotik alanı sade bir alanla değiştirmek isterseniz, bunu yapabilirsiniz:

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

Eğer kullandıysanız Ayrıca bilinmeye değer, trim()dize işlevi (görece yeni) bakmak gerekir strip(), stripLeading()ve stripTrailing()dizeleri üzerinde işlevleri. Her türden küçük boşluk karakterlerini kırpmanıza yardımcı olabilir. Hangi alanın dahil olduğu hakkında daha fazla bilgi için Java'nın Character.isWhitespace()işlevine bakın.


-3

RE'de beyaz boşluk kullanımı bir sıkıntı, ancak işe yaradıklarına inanıyorum. OP'nin sorunu, StringTokenizer veya split () yöntemi kullanılarak da çözülebilir. Ancak, RE'yi kullanmak için (eşleştiricinin Dizeyi nasıl böldüğünü görüntülemek için println () açıklamasını kaldırın), işte örnek bir kod:

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) + "\"");
}}

Aşağıdakileri üretir (javac ile derleyin ve komut isteminde çalıştırın):

% java Two21WS Başlangıç: "ab cdef gh ij kl" Two21WS: "ab cdef gh ij kl"


8
O NE LAN!? Onun replaceAll()yerine arayabilecekken neden tüm bunları yapmak isteyesiniz?
Alan Moore
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.