Question

Y at-il un moyen d'indiquer qui peut se produire deux ou plusieurs phrases regex dans l'ordre? Par exemple, les attributs XML peuvent être écrits dans un ordre quelconque. Dire que j'ai le code XML suivant:

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

Comment puis-je écrire un match qui vérifie la classe et le titre et travaille pour les deux cas? Je cherche principalement pour la syntaxe qui me permet de vérifier dans l'ordre, ne correspond pas à juste titre la classe et que je peux le faire. Est-il possible d'ailleurs que les combinaisons et y compris les reliant avec un « | »?

Modifier :. Ma préférence serait de le faire en une seule regex que je suis construire et aussi tester programatically unité il

Était-ce utile?

La solution

Non, je crois que la meilleure façon de le faire avec un seul RE est exactement comme vous le décrivez. Malheureusement, ça va devenir très confus quand votre XML peut avoir 5 attributs différents, vous donnant une grand de différents REs pour vérifier.

D'autre part, je ne voudrais pas faire cela avec un RE du tout, car ils ne sont pas destinés à être des langages de programmation. Quel est le problème avec l'approche ancienne de l'utilisation d'une bibliothèque de traitement XML?

Si vous êtes requis pour utiliser un RE, cette réponse ne sera probablement pas aider beaucoup, mais je crois en utilisant les bons outils pour le travail.

Autres conseils

Avez-vous envisagé XPath? (Où l'ordre d'attribut n'a pas d'importance)

//a[@class and @title]

Sélectionnera les deux noeuds de <a> comme correspondances valides. La seule réserve étant que l'entrée doit être XHTML (XML bien formée).

Vous pouvez créer un pour chacun des préanalyse les attributs et les brancher sur une regex pour la balise entière. Par exemple, l'expression rationnelle de la balise pourrait être

<a\b[^<>]*>

Si vous utilisez ce sur XML, vous aurez probablement besoin de quelque chose de plus complexe. En soi, cette regex de base correspondra à une étiquette avec zéro ou plusieurs attributs. Ensuite, vous ajoutez un lookhead pour chacun des attributs que vous voulez faire correspondre:

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

Le [^<>]* laisse numériser à l'avance pour l'attribut, mais ne le laissera pas regarder au-delà du support d'angle de fermeture. Correspondant leader des espaces ici dans le test avant deux objectifs: il est plus flexible que correspondant dans la regex de base, et veiller à ce que nous correspondant à un nom d'attribut entier. En les combinant, nous obtenons:

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

Bien sûr, je l'ai fait quelques hypothèses simplificatrices pour un souci de clarté. Je ne permettait pas des espaces autour de signes égal, pour les guillemets simples ou sans guillemets autour des valeurs d'attribut, ou pour crochets dans les valeurs d'attribut (que j'entends est légal, mais je ne l'ai jamais vu faire). Ces fuites de brancher (si vous avez besoin) fera le plus laid regex, mais ne nécessitera pas des changements à la structure de base.

Vous pouvez utiliser des groupes nommés pour tirer les attributs de la balise. Exécutez le regex et ensuite en boucle sur les groupes faisant tout les tests que vous avez besoin.

Quelque chose comme ça (non testé, en utilisant la syntaxe .net regex avec le \ w pour les caractères de mots et \ s pour les espaces):

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

La façon la plus simple serait d'écrire un regex qui capte la partie <a .... >, puis écrire deux regexes de sortir de la classe et le titre. Bien que vous pourriez probablement faire avec un seul regex, il serait très compliqué, et probablement beaucoup plus d'erreurs.

vous avec un regex besoin de quelque chose comme

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

Ce qui est juste une première estimation de la main sans vérifier si elle est encore valide. Beaucoup plus facile de diviser et conquérir le problème.

Une première solution ad hoc pourrait être de faire ce qui suit.

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

Ceci est loin d'être parfait, car il permet à chaque attribut de se produire plus d'une fois. Je ne pouvais imaginer que cela pourrait être solveable avec des affirmations. Mais si vous voulez juste extraire les attributs que cela pourrait déjà être sufficent.

Si vous voulez faire correspondre une permutation d'un ensemble d'éléments, vous pouvez utiliser une combinaison de références arrière et zéro largeur correspondant avant négatif.

Dites que vous voulez faire correspondre l'une de ces six lignes:

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

Vous pouvez le faire avec l'expression rationnelle suivante:

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

Les références arrières (\1, \2), vous permettent de vous référer à votre précédents, et le zéro largeur correspondant avant ((?!...)) vous permet de niez un match de position, en disant ne correspondent pas si le contenu matchs à ce poste. La combinaison des deux fait en sorte que votre match est une permutation legit des éléments donnés, chaque possibilité que une fois se produisant.

Ainsi, par exemple, en 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/)

Pour une permutation de cinq éléments, il serait:

/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

Pour exemple, l'expression rationnelle serait

/<a href="home.php" (class="link"|title="Home") (?!\1)(class="link"|title="Home")>Home<\/a>/
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top