2012-04-20 11 views
8

OK, chicos. Aquí hay una pregunta del tipo de entrevista de Java que parece haber dejado perplejos a algunas personas muy inteligentes por aquí. De hecho, necesitan esto para el código de producción, por lo que es más que un rompecabezas de entrevistas.Java RegEx que coincide con cualquier cosa PERO cadena literal 'NIL' o 'nil'

Necesitan una expresión regular, en Java, que devuelve verdadero si una cadena literal es cualquier cosa que no sea la palabra de 3 letras NIL. La prueba debe ser insensible a las mayúsculas y minúsculas, y el RegEx mismo debe hacer todo el trabajo.

Por lo tanto, el RegEx debe rechazar NIL, nil, NiL, nIL, y así sucesivamente.

Debe, sin embargo, aceptar: nile, anil, will, zappa-nil-a, y la cadena vacía.

¿Cuántos desarrolladores de Java se necesitan para escribir un RegEx trivial? Aparentemente mucho!

+0

+1 para esa parte en cursiva allí, Armchair Bronco buddy. – Kaz

Respuesta

18

Puede hacerlo usando negative lookahead.

Con la opción de mayúsculas y minúsculas habilitados:

^(?!nil$).* 

Se podría dejar fuera de la .* al final si no es necesario para volver realidad la cadena en el partido. He aquí una versión sin la opción de mayúsculas y minúsculas:

^(?![nN][iI][lL]$).* 

Explicación:

^  # start of string anchor 
(?!  # start negative lookahead (fail if...) 
    nil # literal characters 'nil' 
    $  # end of string 
)  # end lookahead 
.*  # consume string (not necessary, but it acts more like a typical regex) 

Si desea la expresión regular para que coincida con nil\n, a continuación, utilizar \z en lugar de $ en la búsqueda hacia delante: ^(?!nil\z).*

+0

Según uno de los desarrolladores principales de este problema candente, el código en su primer ejemplo^(? Nil $). * Funcionará si se modifica de la siguiente manera: "^ (? I) (? Nil $). * Extra Se requiere un bit en el frente porque no tenemos control sobre las opciones del compilador, por lo que el RegEx tiene que hacer este trabajo por sí mismo. –

+0

Aceptando esto como la respuesta. Tenga en cuenta que agregamos (?) al frente del RegEx, justo después "^" –

+1

@ArmchairBronco 'Tenga en cuenta que agregamos (? I)' Sí, es por eso que Andrew dijo a [habilite la coincidencia insensible a mayúsculas y minúsculas] (http://www.rexegg.com/regex-modifiers.html#i). Hay dos maneras de hacer esto en Java: '(? I)' y 'Pattern.CASE_INSENSITIVE' – zx81

5

Aquí hay una expresión regular verdadera para esto, una que especifica directamente un autómata finito que puede ser alimentado con los caracteres de la cadena uno por uno y alcanzará un estado de aceptación si la cadena no es una variante de NIL:

(|.|..|[^Nn]..|.[^Ii].|..[^Ll]|....+) 

Esto funcionará en los motores de expresiones regulares clásicos que no aplican los cortes de consulta en torno, y se puede convertir en un DFA extraordinariamente rápido.

Puede que tenga que anclar esto con ^ y $, dependiendo de qué tipo de función de expresiones regulares se utiliza este con: (cadena entera) semántica de los partidos, o subcadenas la semántica de búsqueda.

Por ejemplo, prueba de grep:

# rejects lines like nIl and NiL but accepts all else 
# including blank lines: 

grep -E '^(|.|..|[^Nn]..|.[^Ii].|..[^Ll]|....+)$' 

La idea aquí es que:

  1. Todas las cadenas de longitud uno, dos, o cuatro o más partido.
  2. Una cadena de tres caracteres coincide si y solo si:
    1. No comienza con N o n; o
    2. No tiene un yo o yo en el medio; o
    3. No tiene una L o l al final.

Cómo se rechazan NIL y Cero es que no todas las tres reglas 2.1, 2.2 y 2.3. NIL comienza con una N, por lo que falla 2.1. Tiene un I en el medio, por lo que falla 2.2, y tiene una L al final, por lo que falla 2.3.

+0

Puedes poner eso en el tubo de tu" desarrollador principal "y que lo fume durante un rato, jaja :) :) – Kaz

+0

Gracias por el retroalimentación, Kaz. No estoy seguro de si fuma, pero me aseguraré de que tenga un olor a este nuevo tabaco. Aprecio tanto el enfoque alternativo como la explicación. –

Cuestiones relacionadas