Domanda

Esiste un modo per indicare che due o più frasi regex possono verificarsi in qualsiasi ordine?Ad esempio, gli attributi XML possono essere scritti in qualsiasi ordine.Diciamo che ho il seguente XML:

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

Come scriverei una corrispondenza che controlli la classe e il titolo e funzioni in entrambi i casi?Sto principalmente cercando la sintassi che mi permetta di controllare in qualsiasi ordine, non solo abbinando la classe e il titolo come posso fare.Esiste un altro modo oltre a includere semplicemente entrambe le combinazioni e collegarle con un "|"?

Modificare:La mia preferenza sarebbe farlo in una singola regex poiché lo sto costruendo in modo programmatico e anche testandolo in unità.

È stato utile?

Soluzione

No, credo che il modo migliore per farlo con un singolo RE sia esattamente come descrivi.Sfortunatamente, la situazione diventerà molto complicata quando il tuo XML potrà avere 5 attributi diversi, dandoti a grande numero di RE diverse da controllare.

D'altra parte, non lo farei affatto con una RE poiché non sono pensati per essere linguaggi di programmazione.Cosa c'è di sbagliato nell'approccio vecchio stile che prevede l'utilizzo di una libreria di elaborazione XML?

Se tu sei necessario per utilizzare una RE, questa risposta probabilmente non sarà di grande aiuto, ma credo nell'utilizzo degli strumenti giusti per il lavoro.

Altri suggerimenti

Avete considerato XPath? (In cui l'ordine attributo non importa)

//a[@class and @title]

Sarà selezionare entrambi i nodi <a> come le partite valide. L'unica avvertenza è che l'ingresso deve essere xhtml (XML ben formato).

È possibile creare un lookahead per ciascuno degli attributi e inserirli in un'espressione regolare per tutta la tag. Ad esempio, l'espressione regolare per il tag potrebbe essere

<a\b[^<>]*>

Se stai usando questo su XML avrete probabilmente bisogno di qualcosa di più elaborato. Di per sé, questa espressione regolare di base corrisponderà un tag con zero o più attributi. Poi si aggiunge un lookhead per ciascuno degli attributi che si desidera abbinare:

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

Il [^<>]* consente di eseguire la scansione avanti per l'attributo, ma non permetterà che lo sguardo al di là della parentesi angolare di chiusura. Adattamento del spazi leader qui nel lookahead serve a due scopi: è più flessibile di corrispondenza nel regex base, e assicurare che stiamo corrispondenza un intero nome di attributo. La loro combinazione otteniamo:

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

Naturalmente, ho fatto alcune ipotesi semplificative per motivi di chiarezza. Non mi permetto di spazi bianchi intorno al segni di uguaglianza, per apici singoli o senza virgolette intorno ai valori degli attributi, o per le parentesi angolari nei valori degli attributi (che ho sentito è legale, ma non ho mai visto fare). Inserendo queste perdite (se è necessario) farà la più brutta espressione regolare, ma non richiede modifiche alla struttura di base.

Si potrebbe utilizzare gruppi denominati per tirare fuori gli attributi del tag. Eseguire l'espressione regolare e quindi un ciclo sui gruppi di fare qualunque test di cui avete bisogno.

Qualcosa di simile (non testato, utilizzando la sintassi regex .net con l'\ w per i caratteri di parole e \ s per gli spazi bianchi):

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

Il modo più semplice sarebbe quella di scrivere una regex che raccoglie la parte <a .... >, e poi scrivere due espressioni regolari per tirare fuori la classe e il titolo. Anche se probabilmente si potrebbe fare con un unico regex, sarebbe molto complicato, e probabilmente molto più soggetto a errori.

Con un unico regex si avrebbe bisogno di qualcosa come

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

Il che è solo una prima ipotesi mano senza controllare per vedere se è ancora valido. Molto più facile da dividere e conquistare solo il problema.

Una prima soluzione ad hoc potrebbe essere quella di fare quanto segue.

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

Questo è ben lungi dall'essere perfetto, perché permette ad ogni attributo a verificarsi più di una volta. Ho potuto immaginare che questo potrebbe essere solveable con asserzioni. Ma se si desidera solo per estrarre gli attributi che questo potrebbe già essere autosufficiente tra.

Se si desidera far corrispondere una permutazione di un insieme di elementi, è possibile utilizzare una combinazione di riferimenti all'indietro e di ampiezza zero corrispondenza in avanti negativo.

Dire che si desidera abbinare uno di questi sei linee:

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

Si può fare questo con la seguente espressione regolare:

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

I riferimenti posteriori (\1, \2), consentono di riferimento al vostro partite precedenti, e lo zero Larghezza di corrispondenza in avanti ((?!...)) consente si nega una corrispondenza posizionale, dicendo non corrispondono se il contenute le partite in questa posizione. Combinando i due fa in modo che il tuo partner è una permutazione legit degli elementi indicati, con ogni possibilità sola volta occuring.

Così, per esempio, in Ruby:

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/)

Per una permutazione di cinque elementi, sarebbe:

/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

Per il vostro esempio, la regex sarebbe

/<a href="home.php" (class="link"|title="Home") (?!\1)(class="link"|title="Home")>Home<\/a>/
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top