¿Qué es un límite de palabra en regex?

137

Estoy usando expresiones regulares Java en Java 1.6 (para analizar la salida numérica, entre otros propósitos) y no puedo encontrar una definición precisa de \b("límite de palabra"). Supuse que -12sería una "palabra entera" (emparejada por \b\-?\d+\b) pero parece que esto no funciona. Estaría agradecido de saber formas de unir números separados por espacios.

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
peter.murray.rust
fuente
¿Puedes publicar un pequeño ejemplo con entrada y salida esperada?
Brent escribe el código el
Ejemplo Pattern pattern = Pattern.compile ("\\ s * \\ b \\ -? \\ d + \\ s *"); Cadena más = "12"; System.out.println ("" + pattern.matcher (plus) .matches ()); Cadena menos = "-12"; System.out.println ("" + pattern.matcher (minus) .matches ()); pattern = Pattern.compile ("\\ s * \\ -? \\ d + \\ s *"); System.out.println ("" + pattern.matcher (minus) .matches ()); da: verdadero falso verdadero
peter.murray.rust

Respuestas:

97

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

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

brianary
fuente
35
Correctamundo \bes una aserción de ancho cero que coincide si hay \wen un lado y si hay \Wen el otro o la posición es el comienzo o el final de la cadena. \wse define arbitrariamente como caracteres "identificadores" (alnums y guiones bajos), no como algo especialmente útil para el inglés.
hobbs
100% correcto Disculpas por no solo comentar el tuyo. Presioné enviar antes de ver tu respuesta.
Brent escribe el código el
55
en aras de la comprensión, es posible reescribir la expresión regular \bhello\bsin utilizar \b(usando \w, \Wy otros)?
David Portabella
55
Más (^|\W)hello($|\W)o menos : excepto que no capturaría ningún carácter que no sea una palabra antes y después, por lo que sería más parecido (^|(?<=\W))hello($|(?=\W))(usando afirmaciones de búsqueda anticipada / posterior).
brianary
66
@brianary un poco más sencillo: (?<!\w)hello(?!\w).
David Knipe
28

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 de 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 palabras son alfanuméricos; un signo menos no lo es. Tomado de Regex Tutorial .

WolfmanDragon
fuente
21

En el curso de aprendizaje de la expresión regular, que era realmente atascado en el metacarácter que es \b. De hecho, no comprendí su significado mientras me preguntaba " qué es, qué es " repetidamente. Después de algunos intentos al usar el sitio web , observo los guiones verticales de color rosa al comienzo de cada palabra y al final de las palabras. Lo entendí bien en ese momento. Ahora es exactamente word ( \w) -boundary .

Mi opinión es meramente orientada a la comprensión inmensa. La lógica detrás de esto debe examinarse a partir de otras respuestas.

ingrese la descripción de la imagen aquí

snr
fuente
3
Un muy buen sitio para entender qué es un límite de palabras y cómo están sucediendo las
coincidencias
2
Esta publicación merece crédito por mostrar en lugar de contar. Una imagen vale más que mil palabras.
M_M
13

Un límite de palabra es una posición precedida por un carácter de palabra y no seguida por una, o seguida de un carácter de palabra y no precedida por una.

Alan Moore
fuente
8

Hablo acerca de qué \blímites de expresión regular de estilo hay realmente aquí .

La historia corta es que son condicionales . Su comportamiento depende de lo que están al lado.

# 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 quieres. Vea mi otra respuesta para más detalles.

tchrist
fuente
7

Me gustaría explicar la respuesta de Alan Moore

Un límite de palabra es una posición precedida por un carácter de palabra y no seguida por una o seguida por un carácter de palabra y no precedida por una.

Supongamos que tengo una cadena "Esto es una c a t, y ella es una maravillosa", y se supone que debo reemplazar todas las ocurrencias de la letra 'a' solo si esta letra existe en el "Límite de una palabra" , es decir la letra adentro de 'gato' no debe ser reemplazada.

Así que realizaré expresiones regulares (en Python ) como

re.sub("\ba","e", myString.strip())// reemplazar acone

por lo que la salida será Esto es ec un t end ella de ewesome

Daksh Gargas
fuente
5

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

De todos modos, esto es lo que descubrí (resumido principalmente en http://www.regular-expressions.info , que es un gran sitio): en la mayoría de los sabores de expresiones regulares, los caracteres que coinciden con la clase de caracteres abreviados \wson los caracteres que se tratan como caracteres de palabras por límites de palabras. Java es una excepción. Java admite Unicode para \bpero no para \w. (Estoy seguro de que había una buena razón para ello en ese momento).

Las \wsiglas de "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, \wincluye muchos caracteres de otros scripts. Hay mucha inconsistencia sobre qué personajes están realmente incluidos. Generalmente se incluyen letras y dígitos de scripts alfabéticos e ideógrafos. Los signos de puntuación del conector que no sean el subrayado y los símbolos numéricos que no son dígitos pueden o no estar incluidos. El esquema XML y XPath incluso incluyen todos los símbolos \w. Pero Java, JavaScript y PCRE solo coinciden con los caracteres ASCII \w.

Es por eso que las búsquedas de expresiones regulares basadas en Java buscan C++, C#o .NET(incluso cuando recuerdas escapar del período y las ventajas) se atornillan\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 esos lenguajes con nombres extraños, debe reemplazarlo \bcon espacios en blanco y designadores de puntuación antes y después. 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));

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

Tihamer
fuente
C#
Luché
4

Consulte la documentación sobre condiciones de contorno:

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

Mira 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 lo imprima, observe que el resultado es este:

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

Esto significa que el carácter "-" no se selecciona como el límite de una palabra porque no se considera un carácter de palabra. Parece que @brianary me dio una paliza, por lo que recibe un voto positivo.

Brent escribe el código
fuente
2

El límite de palabra \ b se usa donde una palabra debe ser un carácter de palabra y otra un carácter que no sea de palabra. La expresión regular para número negativo debe ser

--?\b\d+\b

comprobar DEMO de trabajo

Anubhav Shakya
fuente
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 la palabra coincidirá después de- y, por lo tanto, no lo capturará. Los límites de palabras coinciden antes del primero y después de los últimos caracteres de una cadena, así como en cualquier lugar donde antes sea un carácter de palabra o un carácter que no sea de palabra, y después es lo contrario. También tenga en cuenta que el límite de palabra es una coincidencia de ancho cero.

Una alternativa posible es

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

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

Sean
fuente
0

Creo que es el límite (es decir, el seguimiento de caracteres) de la última coincidencia o el comienzo o el final de la cadena.


fuente
1
Estás pensando en \G: coincide con el comienzo 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.
Alan Moore
0

cuando usa \\b(\\w+)+\\beso significa coincidencia exacta con una palabra que contiene solo caracteres de palabras([a-zA-Z0-9])

en su caso, por ejemplo entorno \\ba principios de expresiones regulares aceptará -12(con espacio) pero de nuevo no aceptará -12(sin espacio)

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

vic
fuente