2009-08-24 15 views
69

Estoy usando expresiones regulares de Java en Java 1.6 (inter alia para analizar la salida numérica) y no puedo encontrar una definición precisa de \b ("límite de palabras"). Había asumido que -12 sería una "palabra entera" (emparejada por \b\-?\d+\b) pero parece que esto no funciona. Estaría agradecido de saber cómo se pueden combinar los números separados por espacios.¿Qué es un límite de palabras en expresiones regulares?

Ejemplo:

Pattern pattern = Pattern.compile("\\s*\\b\\-?\\d+\\s*"); 
String plus = " 12 "; 
System.out.println(""+pattern.matcher(plus).matches()); 
String minus = " -12 "; 
System.out.println(""+pattern.matcher(minus).matches()); 
pattern = Pattern.compile("\\s*\\-?\\d+\\s*"); 
System.out.println(""+pattern.matcher(minus).matches()); 

Esto devuelve:

true 
false 
true 
+0

¿se puede poner un pequeño ejemplo con entrada y salida esperada? –

+0

Intentaremos construir uno –

+0

Ejemplo \t Patrón de patrón = Pattern.compile ("\\ s * \\ b \\ -? \\ d + \\ s *"); \t String plus = "12"; \t System.out.println ("" + pattern.matcher (plus) .matches()); \t Cadena minus = "-12"; \t System.out.println ("" + pattern.matcher (menos) .matches()); \t pattern = Pattern.compile ("\\ s * \\ -? \\ d + \\ s *"); \t System.out.println ("" + pattern.matcher (menos) .matches()); gives: true false true –

Respuesta

48

Un límite de palabra, en la mayoría de dialectos de expresiones regulares, es una posición entre \w y \W (char no-palabra), o al principio o al final de una cadena si comienza o termina (respectivamente) con un carácter de palabra ([0-9A-Za-z_])

Por lo tanto, en la cadena "-12", coincidiría antes del 1 o después del 2. El guión no es un carácter de palabra.

+17

Correctamundo. '\ b' es una aserción de ancho cero que coincide si hay' \ w' en un lado, y ya sea '\ W' en el otro o la posición es principio o fin de cadena. '\ w' se define arbitrariamente como caracteres" identificadores "(alnums y guiones bajos), no como algo especialmente útil para el inglés. – hobbs

+0

100% correcto. Disculpas por no solo comentar sobre los tuyos. Pulso enviar antes de ver su respuesta. –

+1

por el bien de la comprensión, ¿es posible reescribir la expresión regular '\ bhello \ b' sin usar' \ b' (usando '\ w',' \ W' y otra)? –

0

creo que es el límite (es decir, el carácter siguiente) del último partido o al principio o al final de la cadena.

+1

Estás pensando en '\ G': coincide con el principio de la cadena (como' \ A') en el primer intento de coincidencia; después de eso, coincide con la posición donde terminó el partido anterior. –

1

Creo que su problema se debe al hecho de que - no es un carácter de palabra. Por lo tanto, el límite de palabras coincidirá después del -, por lo que no lo capturará. Los límites de palabras coinciden antes que el primero y después de los últimos caracteres de una cadena, así como cualquier lugar donde antes sea un carácter de palabra o un carácter que no sea una palabra, y después es lo contrario. También tenga en cuenta que el límite de palabras es una coincidencia de ancho cero.

Una alternativa posible es

(?:(?:^|\s)-?)\d+\b 

Esto coincidirá con cualquier números que comiencen con un carácter de espacio y un guión opcional, y que termina en un límite de palabra. También coincidirá con un número que comienza al comienzo de la cadena.

4

Mira la documentación sobre las condiciones de contorno:

http://java.sun.com/docs/books/tutorial/essential/regex/bounds.html

Salida esta muestra:

public static void main(final String[] args) 
    { 
     String x = "I found the value -12 in my string."; 
     System.err.println(Arrays.toString(x.split("\\b-?\\d+\\b"))); 
    } 

Cuando se imprima, observe que la salida es la siguiente:

[Encontré el valor -, en mi cadena.]

Esto significa que el carácter "-" no se está recogiendo como que está en el límite de una palabra porque no se considera un carácter de palabra. Parece que @brianary me ganó un poco, así que recibe un voto positivo.

13

Un límite de palabra puede ocurrir en una de tres posiciones:

  1. Antes del primer carácter de la cadena, si el primer carácter es un carácter de palabra.
  2. Después del último carácter en la cadena, si el último carácter es un carácter de palabra.
  3. Entre dos caracteres en la cadena, donde uno es un carácter de palabra y el otro no es un carácter de palabra.

Los caracteres de palabra son alfanuméricos; un signo menos no es. Tomado de Regex Tutorial.

3

Un límite de palabras es una posición que está precedida por un carácter de palabra y no seguido por uno, ni seguido por un carácter de palabra ni precedido por uno.

+0

Esta es la mejor explicación. –

4

Hablo de lo que \b-style regex boundaries en realidad son here.

La historia corta es que son condicional. Su comportamiento depende de lo que están próximos.

# same as using a \b before: 
(?(?=\w) (?<!\w) | (?<!\W)) 

# same as using a \b after: 
(?(?<=\w) (?!\w) | (?!\W) ) 

A veces eso no es lo que desea. Vea mi otra respuesta para la elaboración.

4

me encontré con un problema aún peor cuando la búsqueda de texto de palabras como .NET, C++, C#, y C. Uno pensaría que los programadores de computadoras sabrían mejor que nombrar un idioma para el cual es difícil escribir expresiones regulares.

De todos modos, esto es lo que he descubierto (que se resumen en su mayoría de http://www.regular-expressions.info, que es un gran sitio): En la mayoría de los sabores de expresiones regulares, caracteres que se corresponden con la clase de caracteres taquigrafía \w son los personajes que se tratan como personajes de palabras por límites de palabras. Java es una excepción. Java admite Unicode para \b pero no para \w. (Estoy seguro de que había una buena razón para eso en ese momento).

El \w significa "carácter de palabra". Siempre coincide con los caracteres ASCII [A-Za-z0-9_]. Observe la inclusión del guión bajo y los dígitos (¡pero no el guión!). En la mayoría de los sabores que admiten Unicode, \w incluye muchos caracteres de otros scripts. Hay mucha inconsistencia acerca de qué personajes están realmente incluidos. Por lo general, se incluyen letras y dígitos de scripts alfabéticos e ideogramas. La puntuación del conector que no sea el guión bajo y los símbolos numéricos que no son dígitos pueden o no estar incluidos. XML Schema y XPath incluso incluyen todos los símbolos en \w. Pero Java, JavaScript y PCRE solo coinciden con los caracteres ASCII con \w.

¿Cuál es la razón de Java basada en búsquedas de expresiones regulares para C++, C# o .NET (incluso cuando se recuerda a escapar del período y ventajas) están atornillados por el \b.

Nota: No estoy seguro de qué hacer con los errores en el texto, como cuando alguien no pone un espacio después de un punto al final de una oración. Lo permití, pero no estoy seguro de que sea necesariamente lo correcto.

De todos modos, en Java, si está buscando texto para los idiomas con nombres extraños, debe reemplazar el \b con el antes y el después del espacio en blanco y los designadores de puntuación. Por ejemplo:

public static String grep(String regexp, String multiLineStringToSearch) { 
    String result = ""; 
    String[] lines = multiLineStringToSearch.split("\\n"); 
    Pattern pattern = Pattern.compile(regexp); 
    for (String line : lines) { 
     Matcher matcher = pattern.matcher(line); 
     if (matcher.find()) { 
      result = result + "\n" + line; 
     } 
    } 
    return result.trim(); 
} 

Luego, en su prueba o función principal:

String beforeWord = "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|^)"; 
    String afterWord = "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|$)"; 
    text = "Programming in C, (C++) C#, Java, and .NET."; 
    System.out.println("text="+text); 
    // Here is where Java word boundaries do not work correctly on "cutesy" computer language names. 
    System.out.println("Bad word boundary can't find because of Java: grep with word boundary for .NET="+ grep("\\b\\.NET\\b", text)); 
    System.out.println("Should find: grep exactly for .NET="+ grep(beforeWord+"\\.NET"+afterWord, text)); 
    System.out.println("Bad word boundary can't find because of Java: grep with word boundary for C#="+ grep("\\bC#\\b", text)); 
    System.out.println("Should find: grep exactly for C#="+ grep("C#"+afterWord, text)); 
    System.out.println("Bad word boundary can't find because of Java:grep with word boundary for C++="+ grep("\\bC\\+\\+\\b", text)); 
    System.out.println("Should find: grep exactly for C++="+ grep(beforeWord+"C\\+\\+"+afterWord, text)); 

    System.out.println("Should find: grep with word boundary for Java="+ grep("\\bJava\\b", text)); 
    System.out.println("Should find: grep for case-insensitive java="+ grep("?i)\\bjava\\b", text)); 
    System.out.println("Should find: grep with word boundary for C="+ grep("\\bC\\b", text)); // Works Ok for this example, but see below 
    // Because of the stupid too-short cutsey name, searches find stuff it shouldn't. 
    text = "Worked on C&O (Chesapeake and Ohio) Canal when I was younger; more recently developed in Lisp."; 
    System.out.println("text="+text); 
    System.out.println("Bad word boundary because of C name: grep with word boundary for C="+ grep("\\bC\\b", text)); 
    System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text)); 
    // Make sure the first and last cases work OK. 

    text = "C is a language that should have been named differently."; 
    System.out.println("text="+text); 
    System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text)); 

    text = "One language that should have been named differently is C"; 
    System.out.println("text="+text); 
    System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text)); 

    //Make sure we don't get false positives 
    text = "The letter 'c' can be hard as in Cat, or soft as in Cindy. Computer languages should not require disambiguation (e.g. Ruby, Python vs. Fortran, Hadoop)"; 
    System.out.println("text="+text); 
    System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text)); 

P. S. ¡Gracias a http://regexpal.com/ sin el cual el mundo regex sería muy miserable!

+0

Tuve problemas tratando de entender por qué no podía hacer coincidir 'C#' pero ahora está más claro –

0

cuando se utiliza \\b(\\w+)+\\b que significa coincidencia exacta con una palabra que sólo contiene caracteres de palabra ([a-zA-Z0-9])

en su caso, para el establecimiento de \\b a principios de expresiones regulares aceptará -12 (con espacio) ejemplo pero de nuevo no aceptará -12 (sin espacio)

de referencia para apoyar mis palabras: https://docs.oracle.com/javase/tutorial/essential/regex/bounds.html

Cuestiones relacionadas