utilizar solo regulares regular rango probar numeros letras extraer expresiones expresion especiales con como caracteres cadenas java regex verbose

solo - extraer cadenas con expresiones regulares java



Error al compilar una expresión regular de Java detallada con clase de caracteres y límite de palabra (5)

¿Por qué este patrón no se compila:

Pattern.compile("(?x)[ ]//b");

Error

ERROR java.util.regex.PatternSyntaxException: Illegal/unsupported escape sequence near index 8 (?x)[ ]/b ^ at java_util_regex_Pattern$compile.call (Unknown Source)

¿Mientras que los siguientes equivalentes funcionan?

Pattern.compile("(?x)// //b"); Pattern.compile("[ ]//b"); Pattern.compile(" //b");

¿Es esto un error en el compilador de expresiones regulares de Java, o me estoy perdiendo algo? Me gusta usar [ ] en expresiones regulares verbales en lugar de backslash-backslash-space porque guarda algo de ruido visual. Pero aparentemente no son lo mismo!

PD: este problema no es sobre barras invertidas. Se trata de escapar de espacios en una expresión regular verbosa usando una clase de caracteres que contiene un solo espacio [ ] lugar de usar una barra invertida.

De alguna manera, la combinación de expresiones regulares (?x) y una clase de caracteres que contiene un solo espacio [ ] desactiva el compilador y hace que no reconozca el límite de la palabra escape /b

Probado con Java hasta 1.8.0_151


Me gusta usar [ ] en expresiones regulares verbales en lugar de backslash-backslash-space porque guarda algo de ruido visual. Pero aparentemente no son lo mismo!

"[ ]" es lo mismo que "// " o incluso " " .

El problema es que (?x) al principio habilita el modo de comentarios . Como indica la documentation

Permite espacios en blanco y comentarios en patrón.
En este modo, el espacio en blanco se ignora y los comentarios incrustados que comienzan con # se ignoran hasta el final de una línea.
El modo de comentarios también se puede habilitar a través de la expresión de bandera incrustada (?x) .

En el modo de comentarios, la expresión regular "(?x)[ ]//b" es lo mismo que "[]//b" y no se compilará porque la clase de caracteres vacíos [] no se analiza como vacía, sino que se analiza como "[//]" (clase de caracteres no cerrados que contiene un literal ] ).

Utilice " //b" lugar. Alternativamente, puede preservar el espacio en el modo de comentarios escapándolo con una barra invertida: "(?x)[// ]//b" o "(?x)// //b" .


Una solución

Además de los espacios en blanco que se escapan por separado que son literalmente lo mismo que [ ] , puede tener x modo x para las expresiones regulares completas pero deshabilitarlo mientras trabaja en patrones que necesitan espacios en blanco, en línea:

(?x)match-this-(?-x: with spaces )//b ^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^ `x` is on off on

o una alternativa sería usar los meta-caracteres qouting /Q.../E :

(?x)match-this-/Q with s p a c e s /E//b ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^ `x` is on off on

¿Por qué una Exception ?

En el modo extendido o de comentario ( x ), los espacios en blanco se ignoran pero el manejo de espacios dentro de clases de caracteres en varios tipos se maneja de manera diferente.

Por ejemplo, en PCRE, todos los caracteres de espacios en blanco se ignoran, excepto los de una clase de caracteres. Eso significa que [ ] es una expresión regular válida pero Java no tiene una excepción:

En este modo, el espacio en blanco se ignora ...

Período. Entonces, [ ] es igual a este [] que no es válido y lanza una excepción PatternSyntaxException .

Casi todos los tipos de expresiones regulares, excepto JavaScript, necesitan una clase de caracteres para tener al menos una unidad de datos. Tratan una clase de caracteres vacía como un conjunto no cerrado que necesita un corchete de cierre. Dicho esto, []] es válido en la mayoría de los sabores.

Modo de espaciado libre en sabores diferentes en [ ] :

  • PCRE válido
  • .NET válido
  • Perl valido
  • Ruby valido
  • TCL válido
  • Java 7 no válido
  • Java 8 no válido

Analicemos qué sucede exactamente.

Eche un vistazo al código fuente de java.util.regex.Pattern

Permite espacios en blanco y comentarios en patrón. En este modo, el espacio en blanco se ignora y los comentarios incrustados que comienzan con # se ignoran hasta el final de una línea.

El modo de comentarios también se puede habilitar a través de la expresión de bandera incrustada (? X).

Tu regex te guiará en esta line

private void accept(int ch, String s) { int testChar = temp[cursor++]; if (has(COMMENTS)) testChar = parsePastWhitespace(testChar); if (ch != testChar) { throw error(s); } }

Si observa su código, llame a parsePastWhitespace(testChar);

private int parsePastWhitespace(int ch) { while (ASCII.isSpace(ch) || ch == ''#'') { while (ASCII.isSpace(ch))//<----------------Here is the key of your error ch = temp[cursor++]; if (ch == ''#'') ch = parsePastLine(); } return ch; }

En su caso, tiene un espacio en blanco en su expresión regular (?x)[ ]//b esto devolverá algo (no puedo analizarlo correctamente):

if (ch != testChar) { throw error(s); }

que no es igual a ch y aquí una excepción es tirar

throw error(s);


Este es un error en el método peekPastWhitespace() Java en la clase Pattern . Rastreando todo este problema ... Decidí echar un vistazo a la implementación del Pattern OpenJDK 8-b132 . Vamos a empezar a martillar esto desde la parte superior:

  1. compile() llama a expr() en la línea 1696
  2. expr() llama sequence() en línea 1996
  3. sequence() llama a clazz() en la línea 2063 ya que se cumplió el caso de [
  4. clazz() llama a peek() en la línea 2509
  5. peek() llama a peekPastWhitespace() en la línea 1830 ya que if(has(COMMENTS)) evalúa como true (debido a que se agregó la peekPastWhitespace() x (?x) al comienzo del patrón)
  6. peekPastWhitespace() (publicado abajo) salta todos los espacios en el patrón.

peekPastWhitespace()

private int peekPastWhitespace(int ch) { while (ASCII.isSpace(ch) || ch == ''#'') { while (ASCII.isSpace(ch)) ch = temp[++cursor] if (ch == ''#'') { ch = peekPastLine(); } } return ch; }

El mismo error existe en el método parsePastWhitespace() .

Su expresión regular se interpreta como []//b , que es la causa de su error porque /b no es compatible con una clase de caracteres en Java. Además, una vez que solucionas el problema /b , tu clase de personaje tampoco tiene un cierre ] .

Qué puedes hacer para solucionar este problema:

  1. // Como mencionó el OP, simplemente use doble barra invertida y espacio
  2. [// ] Escapa del espacio dentro de la clase de caracteres para que se interprete literalmente
  3. [ ](?x)//b Coloque el modificador en línea después de la clase de caracteres

Parece que debido a que el espacio de espacio libre (detallado) (?x) en [ ] se ignora, por lo que el motor de expresiones regulares ve su expresión regular como []//b .
Si eliminamos //b , se vería como [] y obtendríamos un error sobre la Unclosed character class caracteres no puede estar vacía, por lo que ] coloca directamente después de [ se trata como el primer carácter que pertenece a esa clase en lugar de un símbolo meta que está cerrando clase de personaje.

Por lo tanto, dado que [ está cerrado, el motor de expresiones regulares se considera /b como colocado dentro de esa clase de caracteres. Pero /b no puede colocarse allí (no representa carácter sino "lugar"), por lo que estamos viendo un error sobre "secuencia de escape no admitida" (dentro de la clase de carácter, pero esa parte se omitió).

En otras palabras, no puede usar [ ] para escapar del espacio en modo detallado (al menos en Java). Deberá usar "// " o "[// ]" .