Corrispondenza di corrispondenza di spazi bianchi – Java

L’API Java per le espressioni regolari afferma che \s corrisponderà agli spazi bianchi. Quindi la regex \\s\\s dovrebbe corrispondere a due spazi.

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

Lo scopo di questo è sostituire tutte le istanze di due spazi bianchi consecutivi con un singolo spazio. Tuttavia, questo in realtà non funziona.

Sto avendo un grave fraintendimento delle regex o del termine “spazio bianco”?

Sì, è necessario prendere il risultato di matcher.replaceAll ():

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

Non è ansible utilizzare \s in Java per abbinare lo spazio bianco sul proprio set di caratteri nativi, poiché Java non supporta la proprietà dello spazio bianco Unicode, anche se è strettamente necessario per soddisfare RL1.2 di UTS # 18! Quello che ha non è conforms agli standard, ahimè.

Unicode definisce 26 punti di codice come \p{White_Space} : 20 di questi sono vari tipi di \pZ GeneralCategory = Separator , e i restanti 6 sono \p{Cc} GeneralCategory = Control .

Lo spazio bianco è una proprietà piuttosto stabile, e quelle stesse sono state in circolazione praticamente per sempre. Anche così, Java non ha alcuna proprietà conforms a The Unicode Standard per questi, quindi devi usare un codice come questo:

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

Ora puoi usare whitespace_charclass + "+" come pattern nel tuo replaceAll .


=begin soapbox

Mi dispiace per tutto questo. Le regex di Java non funzionano molto bene con il proprio set di caratteri nativi, quindi è davvero necessario saltare attraverso i cerchi esotici per farli funzionare.

E se pensi che lo spazio bianco sia brutto, dovresti vedere cosa devi fare per ottenere \w e \b per infine comportarti correttamente!

Sì, è ansible, e sì, è un disastro mentale. Anche questo è caritatevole. Il modo più semplice per ottenere una libreria regex standard-comforming per Java è quello di JNI su roba di ICU. Questo è ciò che Google fa per Android, perché OraSun non è all’altezza.

Se non vuoi farlo ma vuoi continuare ad usare Java, ho una libreria di riscrittura regex front-end che ho scritto che “ripara” i pattern di Java, almeno per renderli conformi ai requisiti di RL1.2a in UTS # 18, Unicode Regular Expressions .

=end soapbox

Per Java (non php, non javascript, non altri):

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

Sembra funzionare per me:

 String s = " abc"; System.out.println("\"" + s.replaceAll("\\s\\s", " ") + "\""); 

stamperà:

 " abc" 

Penso che hai intenzione di farlo al posto del tuo codice:

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

quando ho inviato una domanda a un forum Regexbuddy (regex developer application), ho ottenuto una risposta più esatta alla mia domanda Java:

“Autore del messaggio: Jan Goyvaerts

In Java, le combinazioni di tasti \ s, \ d e \ w includono solo caratteri ASCII. … Questo non è un bug in Java, ma semplicemente una delle tante cose di cui devi essere a conoscenza quando lavori con le espressioni regolari. Per abbinare tutti gli spazi bianchi Unicode e le interruzioni di riga, puoi usare [\ s \ p {Z}] in Java. RegexBuddy non supporta ancora proprietà specifiche di Java come \ p {javaSpaceChar} (che corrisponde esattamente agli stessi caratteri di [\ s \ p {Z}]).

… \ s \ s corrisponderà a due spazi, se l’input è solo ASCII. Il vero problema è con il codice OP, come indicato dalla risposta accettata in quella domanda. ”

 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; } } 

Per il tuo scopo puoi usare questo snnippet:

 import org.apache.commons.lang3.StringUtils; StrintUtils.StringUtils.normalizeSpace(string); 

questo normalizzerà la spaziatura in singolo e rimuoverà anche gli spazi bianchi iniziali e finali.

L’uso degli spazi bianchi in RE è un dolore, ma credo che funzionino. Il problema dell’OP può anche essere risolto usando StringTokenizer o il metodo split (). Tuttavia, per usare RE (decommentare println () per vedere come il matcher sta spezzando la stringa), ecco un esempio di codice:

 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 = " ab cdef gh ij kl"; System.out.println ("Initial: \"" + tester + "\""); System.out.println ("Two21WS: \"" + new Two21WS(tester) + "\""); }} 

Produce quanto segue (compila con javac ed esegui al prompt dei comandi):

% java Two21WS Iniziale: “ab cdef gh ij kl” Two21WS: “ab cdef gh ij kl”