Necesito un mecanismo para encontrar un número en una cadena que esté rodeado por caracteres no digitales o el inicio / final de la cadena o un delimitador especial (43 en este caso). Aquí hay unos ejemplos:

  • N ° de pedido 12345678
  • 12345678
  • 12345678blabla
  • 431234567843

Todos estos deberían resultar en una coincidencia de 12345678. Actualmente estoy usando la siguiente expresión regular:

(?<=^|\D|43)([0-9]{8})(?=$|\D|43)

Esta expresión funciona bastante bien, pero tiene un defecto. Si el número comienza con 43 pero no termina con 43, también obtengo un resultado positivo. Aquí hay ejemplos donde obtengo esos resultados 'falsos':

  • 4312345678
  • 4312345678blabla

Lo que necesito ahora es una construcción para que la expresión regular sepa si la cadena coincidente comenzó con 43 y luego solo la devuelve como un resultado positivo si también termina con 43.

1
Romano Zumbé 16 jun. 2017 a las 11:57

2 respuestas

La mejor respuesta

Puede utilizar una verificación anticipada positiva en el reverso:

(?<=^|\D|43(?=[0-9]{8}43))[0-9]{8}(?=43|\D|$)
           ^^^^^^^^^^^^^^

Consulte la demostración de expresiones regulares.

Ahora, la coincidencia solo ocurrirá si 43 es anterior a y después de 8 dígitos aleatorios.

Detalles :

  • (?<=^|\D|43(?=[0-9]{8}43)): coincide con una ubicación en cadena que es inmediatamente precedido de
    • ^ - inicio de cadena
    • \D - un símbolo sin dígitos
    • 43(?=[0-9]{8}43) - 43 subcadena seguida de 8 dígitos y luego 43 subcadena
  • [0-9]{8} - exactamente 8 dígitos
  • (?=43|\D|$) - los 8 dígitos deben seguirse con:
    • 43 - 43 secuencia de dígitos
    • \D - (= [^0-9]) cualquier símbolo que no sea un dígito
    • $ - fin de la cadena.

Y aquí está mi propio expresiones regulares basadas en para la misma tarea (se puede usar en .NET, PCRE, pero no en Java):

(?<=^|[^0-9]|(43))[0-9]{8}(?=(?(1)43|(?:[^0-9]|$)))

Aquí hay una Rege. regexps.

Parte de la información básica sobre Construcción condicional :

Este elemento del lenguaje intenta hacer coincidir uno de los dos patrones dependiendo de si puede coincidir con un patrón inicial. Su sintaxis es:

(?( expression ) yes | no )

donde expresión es el patrón inicial que coincide, sí es el patrón que coincide si la expresión coincide y no es el patrón opcional que coincide si la expresión no coincide. El motor de expresión regular trata la expresión como una aserción de ancho cero; es decir, el motor de expresión regular no avanza en la secuencia de entrada después de evaluar la expresión.

Por lo tanto, el (43) en el retrospectiva se captura en el Grupo 1 y luego, dentro del condicional, (?(1)43|(?:[^0-9]|$)), (?(1)) comprueba si el Grupo 1 coincide en absoluto, y si es así, 43 coincide, de lo contrario, se intenta (?:[^0-9]|$) (cualquier no dígito o el final de la cadena.

3
Wiktor Stribiżew 16 jun. 2017 a las 09:22

Puede usar un condicional:

(?<=^|\D|(43))[0-9]{8}(?(1)(?=43)|(?=$|\D))

El primer 43 se captura en el grupo 1, y luego las consultas condicionales si el grupo 1 coincide con algo.


En caso de que su motor regex no admita condicionales, puede probar esta solución alternativa "haga su propio condicional" :

(?<=^|\D|()43)[0-9]{8}(?=(?:\1(?:43)|(?!\1)(?:\D|$)))

La idea es reemplazar un (text)(?(1)a|b) condicional con una alternancia como esta: ()text(?:\1a|(?!\1)b)

2
Aran-Fey 16 jun. 2017 a las 09:13