Pregunta

¿Hay una manera de indicar que dos o más frases de expresiones regulares pueden ocurrir en cualquier orden? Por ejemplo, los atributos XML se pueden escribir en cualquier orden. Decir que tengo el siguiente código XML:

<a href="home.php" class="link" title="Home">Home</a>
<a href="home.php" title="Home" class="link">Home</a>

¿Cómo puedo escribir un partido que comprueba la clase y el título y trabaja para ambos casos? Busco principalmente para la sintaxis que me permite comprobar en cualquier orden, no sólo con la clase y el título como puedo hacer eso. ¿Hay alguna manera, además de sólo incluye tanto combinaciones y conectándolos con un '|'?

Editar . Mi preferencia sería hacerlo en una sola expresión regular como yo estoy construyendo mediante programación y unidad de pruebas que

¿Fue útil?

Solución

No, creo que la mejor manera de hacerlo con una sola RE es exactamente como se describe. Por desgracia, va a ser muy complicado cuando el código XML puede tener 5 atributos diferentes, que le da un grande número de diferentes RE para comprobar.

Por otra parte, yo no estaría haciendo esto con un RE en absoluto, ya que no están destinados a ser los lenguajes de programación. Lo que está mal con el viejo enfoque de moda de usar una biblioteca de procesamiento de XML?

Si usted es requerida para utilizar un RE, esta respuesta probablemente no ayudará mucho, pero creo que en el uso de las herramientas adecuadas para el trabajo.

Otros consejos

Ha considerado XPath? (Donde el orden de atributos no importa)

//a[@class and @title]

Seleccionará ambos nodos <a> como partidos válidos. La única advertencia es que la entrada debe ser XHTML (XML bien formado).

Puede crear una búsqueda hacia delante para cada uno de los atributos y conectarlos a una expresión regular para toda la etiqueta. Por ejemplo, la expresión regular para la etiqueta podría ser

<a\b[^<>]*>

Si está usando esto en XML es probable que necesite algo más elaborado. Por sí misma, esta expresión regular de base coincidirá con una etiqueta con cero o más atributos. A continuación, se agrega una lookhead para cada uno de los atributos que desea hacer coincidir:

(?=[^<>]*\s+class="link")
(?=[^<>]*\s+title="Home")

El [^<>]* deja explorar hacia delante para el atributo, pero no va a dejar que se vea más allá del soporte del ángulo de cierre. Que coincide con el espacio en blanco que lleva aquí, en la búsqueda hacia delante tiene dos propósitos: es más flexible que el reconocimiento de que en la expresión regular base, y asegurar que estamos coinciden con un nombre de atributo conjunto. La combinación de ellos obtenemos:

<a\b(?=[^<>]*\s+class="link")(?=[^<>]*\s+title="Home")[^<>]+>[^<>]+</a>

Por supuesto, he hecho algunas simplificaciones en aras de la claridad. No permitir el espacio en blanco alrededor del signos de igualdad, por comillas simples o sin comillas alrededor de los valores de los atributos, o para soportes angulares en los valores de los atributos (que he oído es legal, pero nunca he visto hacer). El tapar esas fugas (si es necesario) hará que el más feo de expresiones regulares, pero no se requieren cambios en la estructura básica.

Se puede usar grupos nombrados para tirar de los atributos de la etiqueta. Ejecutar la expresión regular y luego bucle sobre los grupos haciendo lo que las pruebas que necesita.

Algo como esto (no probado, usando la sintaxis de expresiones regulares de .NET con el \ w de caracteres de palabra y \ s de los espacios en blanco):

<a ((?<key>\w+)\s?=\s?['"](?<value>\w+)['"])+ />

La forma más fácil sería escribir una expresión regular que recoge la parte <a .... > y, a continuación, escribir dos expresiones regulares más para sacar la clase y el título. A pesar de que probablemente podría hacerlo con una sola expresión regular, sería muy complicado, y probablemente mucho más propenso a errores.

Con una sola expresión regular que se necesita algo así como

<a[^>]*((class="([^"]*)")|(title="([^"]*)"))?((title="([^"]*)")|(class="([^"]*)"))?[^>]*>

¿Qué es sólo una primera aproximación mano sin la comprobación para ver si es aún válida. Mucho más fácil simplemente dividir y conquistar el problema.

Una primera solución ad hoc podría ser la de hacer lo siguiente.

((class|title)="[^"]*?" *)+

Esto está lejos de ser perfecta, ya que permite a cada atributo que se produzca más de una vez. Me podía imaginar que esto podría ser solveable con las afirmaciones. Pero si lo que desea extraer los atributos esto ya podría ser sufficent.

Si desea hacer coincidir una permutación de un conjunto de elementos, se puede utilizar una combinación de referencias de espalda y de anchura cero coincidente adelante negativo.

Supongamos que desea que coincida con cualquiera de estas seis líneas:

123-abc-456-def-789-ghi-0AB
123-abc-456-ghi-789-def-0AB
123-def-456-abc-789-ghi-0AB
123-def-456-ghi-789-abc-0AB
123-ghi-456-abc-789-def-0AB
123-ghi-456-def-789-abc-0AB

Puede hacer esto con la siguiente expresión regular:

/123-(abc|def|ghi)-456-(?!\1)(abc|def|ghi)-789-(?!\1|\2)(abc|def|ghi)-0AB/

Las referencias anteriores (\1, \2), permiten que se refieren a sus partidos anteriores, y el cero Ancho de juego hacia adelante ((?!...)) le permite el signo de un partido posicional, diciendo no coinciden si el contenida partidos en esta posición. La combinación de los dos se asegura de que su partido es una permutación de fiar de los elementos dados, con cada posibilidad única que ocurren una vez.

Así, por ejemplo, en rubí:

input = <<LINES
123-abc-456-abc-789-abc-0AB
123-abc-456-abc-789-def-0AB
123-abc-456-abc-789-ghi-0AB
123-abc-456-def-789-abc-0AB
123-abc-456-def-789-def-0AB
123-abc-456-def-789-ghi-0AB
123-abc-456-ghi-789-abc-0AB
123-abc-456-ghi-789-def-0AB
123-abc-456-ghi-789-ghi-0AB
123-def-456-abc-789-abc-0AB
123-def-456-abc-789-def-0AB
123-def-456-abc-789-ghi-0AB
123-def-456-def-789-abc-0AB
123-def-456-def-789-def-0AB
123-def-456-def-789-ghi-0AB
123-def-456-ghi-789-abc-0AB
123-def-456-ghi-789-def-0AB
123-def-456-ghi-789-ghi-0AB
123-ghi-456-abc-789-abc-0AB
123-ghi-456-abc-789-def-0AB
123-ghi-456-abc-789-ghi-0AB
123-ghi-456-def-789-abc-0AB
123-ghi-456-def-789-def-0AB
123-ghi-456-def-789-ghi-0AB
123-ghi-456-ghi-789-abc-0AB
123-ghi-456-ghi-789-def-0AB
123-ghi-456-ghi-789-ghi-0AB
LINES

# outputs only the permutations
puts input.grep(/123-(abc|def|ghi)-456-(?!\1)(abc|def|ghi)-789-(?!\1|\2)(abc|def|ghi)-0AB/)

Para una permutación de cinco elementos, sería:

/1-(abc|def|ghi|jkl|mno)-
 2-(?!\1)(abc|def|ghi|jkl|mno)-
 3-(?!\1|\2)(abc|def|ghi|jkl|mno)-
 4-(?!\1|\2|\3)(abc|def|ghi|jkl|mno)-
 5-(?!\1|\2|\3|\4)(abc|def|ghi|jkl|mno)-6/x

Para su ejemplo, la expresión regular sería

/<a href="home.php" (class="link"|title="Home") (?!\1)(class="link"|title="Home")>Home<\/a>/
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top