Whitespace Matching Regex – Java

La API de Java para expresiones regulares establece que \s coincidirá con el espacio en blanco. Entonces los regex \\s\\s deben coincidir con dos espacios.

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

El objective de esto es reemplazar todas las instancias de dos espacios en blanco consecutivos con un solo espacio. Sin embargo, esto en realidad no funciona.

¿Estoy teniendo una grave incomprensión de las expresiones regulares o del término “espacio en blanco”?

Sí, necesitas obtener el resultado de matcher.replaceAll ():

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

No puede usar \s en Java para hacer coincidir el espacio en blanco en su propio juego de caracteres nativo, porque Java no admite la propiedad de espacio en blanco Unicode, ¡aunque hacerlo es estrictamente necesario para cumplir con el RL1.2 de UTS # 18! Lo que sí tiene no es conforme a los estándares, ¡ay!

Unicode define 26 puntos de código como \p{White_Space} : 20 de ellos son varios tipos de \pZ GeneralCategory = Separator , y los 6 restantes son \p{Cc} GeneralCategory = Control .

El espacio en blanco es una propiedad bastante estable, y esos mismos han existido virtualmente para siempre. Aun así, Java no tiene ninguna propiedad que cumpla con el estándar Unicode para estos, por lo que debe 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 + "]"; 

Ahora puede usar whitespace_charclass + "+" como el patrón en su replaceAll .


=begin soapbox

Perdón por todo eso. Las expresiones regulares de Java simplemente no funcionan muy bien en su propio conjunto de caracteres nativos, por lo que realmente tiene que saltar a través de exóticos aros para que funcionen.

¡Y si crees que el espacio en blanco es malo, deberías ver lo que tienes que hacer para que \w y \b finalmente se comporten correctamente!

Sí, es posible, y sí, es un lío paralizante. Eso es ser caritativo, incluso. La forma más fácil de obtener una biblioteca de expresiones regulares que cumpla con los estándares para Java es JNI a las cosas de la ICU. Eso es lo que Google hace para Android, porque OraSun no está a la altura.

Si no quiere hacer eso, pero aún quiere seguir con Java, tengo una biblioteca de reescritura de expresiones regulares de entrada que escribí que “arregla” los patrones de Java, al menos para que se ajusten a los requisitos de RL1.2a en UTS # 18, expresiones regulares Unicode .

=end soapbox

Para Java (no php, no javascript, no anyother):

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

Parece funcionar para mi:

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

se imprimirá:

 " abc" 

Creo que intentaste hacer esto en lugar de tu 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); 

cuando envié una pregunta a un foro de Regexbuddy (aplicación de desarrollador de regex), obtuve una respuesta más exacta a mi pregunta de Java:

“Autor del mensaje: Jan Goyvaerts

En Java, los shorthands \ s, \ d, y \ w solo incluyen caracteres ASCII. … Esto no es un error en Java, sino simplemente una de las muchas cosas que debes tener en cuenta al trabajar con expresiones regulares. Para hacer coincidir todos los espacios en blanco Unicode, así como los saltos de línea, puede usar [\ s \ p {Z}] en Java. RegexBuddy aún no admite propiedades específicas de Java, como \ p {javaSpaceChar} (que coincide exactamente con los mismos caracteres que [\ s \ p {Z}]).

… \ s \ s coincidirá con dos espacios, si la entrada es solo ASCII. El verdadero problema es con el código del OP, como lo señala la respuesta aceptada en esa pregunta “.

 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 su propósito, puede usar este snnippet:

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

esto normalizará el espaciado a single y también eliminará los espacios en blanco iniciales y finales.

El uso del espacio en blanco en RE es un dolor, pero creo que funcionan. El problema del OP también se puede resolver usando StringTokenizer o el método split (). Sin embargo, para usar RE (elimine el comentario de println () para ver cómo el emparejador está dividiendo la cadena), aquí hay un código de muestra:

 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 lo siguiente (comstackr con javac y ejecutar en el símbolo del sistema):

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