Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


¿Qué hace (?! A) {0}? Significa en un regex de Java?

Inspirado por la pregunta de si el cuantificador {0} realmente tiene sentido , empecé a jugar con algunas expresiones regulares que contenían {0} cuantificador y escribí este pequeño programa java que sólo divide una frase de prueba basada en varios regex de prueba:

 private static final String TEST_STR = "Just a test-phrase!! 1.2.3.. @ {(t·e·s·t)}"; private static void test(final String pattern) { System.out.format("%-17s", "\"" + pattern + "\":"); System.out.println(Arrays.toString(TEST_STR.split(pattern))); } public static void main(String[] args) { test(""); test("{0}"); test(".{0}"); test("([^.]{0})?+"); test("(?!a){0}"); test("(?!a).{0}"); test("(?!.{0}).{0}"); test(".{0}(?<!a)"); test(".{0}(?<!.{0})"); } 

==> La salida:

 "": [, J, u, s, t, , a, , t, e, s, t, -, p, h, r, a, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }] "{0}": [, J, u, s, t, , a, , t, e, s, t, -, p, h, r, a, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }] ".{0}": [, J, u, s, t, , a, , t, e, s, t, -, p, h, r, a, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }] "([^.]{0})?+": [, J, u, s, t, , a, , t, e, s, t, -, p, h, r, a, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }] "(?!a){0}": [, J, u, s, t, , a, , t, e, s, t, -, p, h, r, a, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }] "(?!a).{0}": [, J, u, s, t, a, , t, e, s, t, -, p, h, ra, s, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }] "(?!.{0}).{0}": [Just a test-phrase!! 1.2.3.. @ {(t·e·s·t)}] ".{0}(?<!a)": [, J, u, s, t, , a , t, e, s, t, -, p, h, r, as, e, !, !, , 1, ., 2, ., 3, ., ., , @, , {, (, t, ·, e, ·, s, ·, t, ), }] ".{0}(?<!.{0})": [Just a test-phrase!! 1.2.3.. @ {(t·e·s·t)}] 

Lo siguiente no me sorprendió :

  1. "" , ".{0}" , y "([^.]{0})?+" Acaba de dividir antes de cada carácter y que tiene sentido debido a 0-cuantificador.
  2. "(?!.{0}).{0}" y ".{0}(?<!.{0})" no coinciden con nada. Tiene sentido para mí: Negative Lookahead / Lookbehind para 0-token cuantificado no coincidirá.

Lo que me sorprendió :

  1. En realidad, esperaba una Excepción aquí, debido a que el token anterior no era cuantificable: Para {0} simplemente no hay nada precedente y para (?!a){0} No realmente sólo un lookahead negativo. Ambos coinciden justo antes de cada char, ¿por qué? Si intento que regex en un validador javascript, me sale "error no cuantificable", ver la demostración aquí ! ¿Es eso regex manejado diferentemente en Java y Javascript?
  2. "(?!a).{0}" Una pequeña sorpresa también aquí: Los que coinciden antes de cada char de la frase, excepto antes / después de la a . Mi comprensión es que en (?!a).{0} (?!a) La parte (?!a) Negativa mira a la cabeza que es imposible emparejar el a literalmente, pero estoy mirando hacia delante. Pensé que no funcionaría con 0-cuantificado token, pero parece que puedo usar Lookahead con aquellos también.

==> Así que el misterio restante para mí es por qué (?!a){0} es en realidad coincidencia antes de cada char en mi frase de prueba. ¿No debería ser realmente un patrón no válido y lanzar una PatternSyntaxException o algo así?


Actualizar:

Si ejecuto el mismo código Java dentro de una actividad de Android, ¡ el resultado es diferente ! Allí el regex (?!a){0} realmente lanza una PatternSyntaxException, vea:

 03-20 22:43:31.941: D/AndroidRuntime(2799): Shutting down VM 03-20 22:43:31.950: E/AndroidRuntime(2799): FATAL EXCEPTION: main 03-20 22:43:31.950: E/AndroidRuntime(2799): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.appham.courseraapp1/com.appham.courseraapp1.MainActivity}: java.util.regex.PatternSyntaxException: Syntax error in regexp pattern near index 6: 03-20 22:43:31.950: E/AndroidRuntime(2799): (?!a){0} 03-20 22:43:31.950: E/AndroidRuntime(2799): ^ 03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180) 03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230) 03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread.access$600(ActivityThread.java:141) 03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234) 03-20 22:43:31.950: E/AndroidRuntime(2799): at android.os.Handler.dispatchMessage(Handler.java:99) 03-20 22:43:31.950: E/AndroidRuntime(2799): at android.os.Looper.loop(Looper.java:137) 03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread.main(ActivityThread.java:5041) 03-20 22:43:31.950: E/AndroidRuntime(2799): at java.lang.reflect.Method.invokeNative(Native Method) 03-20 22:43:31.950: E/AndroidRuntime(2799): at java.lang.reflect.Method.invoke(Method.java:511) 03-20 22:43:31.950: E/AndroidRuntime(2799): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 03-20 22:43:31.950: E/AndroidRuntime(2799): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 03-20 22:43:31.950: E/AndroidRuntime(2799): at dalvik.system.NativeStart.main(Native Method) 03-20 22:43:31.950: E/AndroidRuntime(2799): Caused by: java.util.regex.PatternSyntaxException: Syntax error in regexp pattern near index 6: 03-20 22:43:31.950: E/AndroidRuntime(2799): (?!a){0} 03-20 22:43:31.950: E/AndroidRuntime(2799): ^ 03-20 22:43:31.950: E/AndroidRuntime(2799): at java.util.regex.Pattern.compileImpl(Native Method) 03-20 22:43:31.950: E/AndroidRuntime(2799): at java.util.regex.Pattern.compile(Pattern.java:407) 03-20 22:43:31.950: E/AndroidRuntime(2799): at java.util.regex.Pattern.<init>(Pattern.java:390) 03-20 22:43:31.950: E/AndroidRuntime(2799): at java.util.regex.Pattern.compile(Pattern.java:381) 03-20 22:43:31.950: E/AndroidRuntime(2799): at java.lang.String.split(String.java:1832) 03-20 22:43:31.950: E/AndroidRuntime(2799): at java.lang.String.split(String.java:1813) 03-20 22:43:31.950: E/AndroidRuntime(2799): at com.appham.courseraapp1.MainActivity.onCreate(MainActivity.java:22) 03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.Activity.performCreate(Activity.java:5104) 03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080) 03-20 22:43:31.950: E/AndroidRuntime(2799): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144) 03-20 22:43:31.950: E/AndroidRuntime(2799): ... 11 more 

¿Por qué regex en Android se comporta diferente de Java simple?

  • Divide la cadena en la última aparición del carácter
  • Regex opcional de límites de palabras de Android
  • Validación de la fecha de Regex para aaaa-mm-dd
  • ¿Cómo lograr límite de palabras en Sqlite Android?
  • ¿Qué regex se puede utilizar para filtrar dalvikvm y dalvikvm-heap mensajes desde el logcat
  • ReplaceAll no reemplaza string
  • Cómo puedo encontrar todas las coincidencias con una expresión regular en android
  • ¿Cómo puedo crear una expresión regular para esto en android?
  • One Solution collect form web for “¿Qué hace (?! A) {0}? Significa en un regex de Java?”

    Hice algunos mirando a la fuente de oráculos java 1.7.

    "{0}"

    He encontrado algún código que lanza "Dangling meta carácter" cuando se encuentra?, * O + en el bucle principal. Es decir, no inmediatamente después de algún grupo literal, "." O en cualquier otro lugar donde se comprueban explícitamente los cuantificadores. Por alguna razón, { no está en esa lista. El resultado es que cae en todas las comprobaciones de caracteres especiales y comienza a analizar para una cadena literal. El primer carácter que encuentra es { , que le dice al analizador que es tiempo de detener el análisis de la cadena literal y comprobar los cuantificadores.

    El resultado es que "{n}" coincidirá con la cadena vacía n veces.

    Otro resultado es que una segunda "x{m}{n}" coincidirá primero con x m veces, y luego hará coincidir la cadena vacía n veces, haciendo caso omiso de la {n} , como mencionó @Kobi en los comentarios anteriores.

    Parece un error para mí, pero no me sorprendería si quieren mantenerlo para compatibilidad con versiones anteriores.

    "(?!a){0}"

    "(?!a)" es sólo un nodo que es cuantificable. Puede comprobar si el siguiente carácter es un 'a' 10 veces. Volverá el mismo resultado cada vez, así que no es muy útil. En nuestro caso, comprobará si el siguiente carácter es 'a' 0 veces, lo que siempre tendrá éxito.

    Tenga en cuenta que como una optimización cuando una coincidencia tiene 0 longitud, como aquí, el cuantificador nunca es codicioso. Esto también evita la recursión infinita en el caso "(?!a)*" .

    "(?!a).{0}" & ".{0}(?<!a)"

    Como se mencionó anteriormente, {0} realiza una comprobación 0 veces, lo que siempre tiene éxito. De hecho, ignora todo lo que viene antes. Eso significa que "(?!a).{0}" es el mismo que "(?!a)" , que tiene el resultado esperado.

    Similar para el otro.

    Android es diferente

    Como se mencionó por @GenericJam, android es una implementación diferente y puede tener características diferentes en estos casos de borde. Intenté mirar esa fuente también, pero androide realmente utiliza código nativo allí 🙂

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.