Regex de correspondência de espaço em branco – Java

A API Java para expressões regulares afirma que \s irá corresponder ao espaço em branco. Portanto, a regex \\s\\s deve corresponder a dois espaços.

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

O objective disso é replace todas as instâncias de dois espaços em branco consecutivos por um único espaço. No entanto, isso não funciona de verdade.

Eu estou tendo um grave mal-entendido de regexes ou o termo “espaço em branco”?

Sim, você precisa pegar o resultado de matcher.replaceAll ():

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

Você não pode usar \s em Java para corresponder ao espaço em branco em seu próprio conjunto de caracteres nativo, porque o Java não suporta a propriedade de espaço em branco Unicode – mesmo que isso seja estritamente necessário para atender à RL1.2 do UTS # 18! O que ele tem não é compatível com os padrões, infelizmente.

Unicode define 26 pontos de código como \p{White_Space} : 20 deles são vários tipos de \pZ GeneralCategory = Separator , e os 6 restantes são \p{Cc} GeneralCategory = Control .

O espaço em branco é uma propriedade bastante estável, e esses mesmos foram virtualmente para sempre. Mesmo assim, o Java não possui nenhuma propriedade que esteja de acordo com o Padrão Unicode para isso, então você precisa usar código como este:

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

Agora você pode usar whitespace_charclass + "+" como o padrão em replaceAll .


=begin soapbox

Desculpe por tudo isso. Os regexes de Java simplesmente não funcionam muito bem em seu próprio conjunto de caracteres nativo, e , portanto, você realmente precisa passar por obstáculos exóticos para fazê-los funcionar.

E se você acha que o espaço em branco é ruim, você deve ver o que tem que fazer para que \w e \b finalmente se comportem corretamente!

Sim, é possível, e sim, é uma confusão mental. Isso é ser caridoso, mesmo. A maneira mais fácil de obter uma biblioteca regex com padrões de conformidade para Java é fazer com que o JNI passe para as coisas do ICU. Isso é o que o Google faz para o Android, porque o OraSun não está à altura.

Se você não quer fazer isso, mas ainda quer ficar com Java, eu tenho uma biblioteca de reescrita regex front-end que escrevi que “corrige” os padrões de Java, pelo menos para obtê-los em conformidade com os requisitos de RL1.2a em UTS # 18, expressões regulares Unicode .

=end soapbox

Para Java (não php, não javascript, não anyother):

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

Parece funcionar para mim:

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

vai imprimir:

 " abc" 

Eu acho que você pretendia fazer isso em vez do seu código:

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

Quando enviei uma pergunta para um fórum do Regexbuddy (aplicativo do desenvolvedor de regex), obtive uma resposta mais exata à pergunta do Java:

“Autor da mensagem: Jan Goyvaerts

Em Java, os atalhos \ s, \ d e \ w incluem apenas caracteres ASCII. … Isso não é um bug no Java, mas simplesmente uma das muitas coisas que você precisa estar ciente ao trabalhar com expressões regulares. Para corresponder a todos os espaços em branco Unicode, bem como as quebras de linha, você pode usar [\ s \ p {Z}] em Java. O RegexBuddy ainda não suporta propriedades específicas de Java, como \ p {javaSpaceChar} (que corresponde exatamente aos mesmos caracteres de [\ s \ p {Z}]).

… \ s \ s irá corresponder dois espaços, se a input for apenas ASCII. O verdadeiro problema é com o código do OP, como é apontado pela resposta aceita nessa questão. ”

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

Para o seu propósito, você pode usar este snnippet:

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

isso normalizará o espaçamento para single e removerá os espaços em branco inicial e final também.

O uso de espaço em branco no ER é uma dor, mas acredito que eles funcionem. O problema do OP também pode ser resolvido usando o StringTokenizer ou o método split (). No entanto, para usar o RE (descomente o println () para ver como o matcher está quebrando a String), aqui está um exemplo de código:

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

Ele produz o seguinte (compilar com javac e executar no prompt de comando):

% java Two21WS Inicial: “ab cdef gh ij kl” Dois21WS: “ab cdef gh ij kl”