2010-10-18 41 views
2

J'ai un problème avec regex, en utilisant preg_match_all(), pour faire correspondre quelque chose d'une longueur variable.Problème Regex: impossible de faire correspondre un modèle de longueur variable

Ce que je suis en train de faire correspondre est la condition de la circulation après le mot « Congestion » Ce que je suis venu avec est ce modèle regex:

Congestion\s*:\s*(?P<congestion>.*)

Il serait cependant extraire d'abord tout le chemin à la fin du sujet entier, puisque. * correspondrait à tout. Mais ce n'est pas ce que je veux, je voudrais que cela corresponde séparément à 3 instances.

Or, puisque les mots derrière Congestion pourraient être de longueur variable, je ne peux pas vraiment prédire combien de mots et les espaces sont entre les deux pour arriver à une plus stricte \ w * \ s * \ w * correspondance, etc.

Des indices sur la façon dont je peux procéder à partir d'ici?

Highway : Highway 26 
Datetime : 18-Oct-2010 05:18 PM 
Congestion : Traffic is slow from Smith St to Alice Springs St 

Highway : Princes Highway 
Datetime : 18-Oct-2010 05:18 PM 
Congestion : Traffic is slow at the Flinders St/Elizabeth St intersection 

Highway : Eastern Freeway 
Datetime : 18-Oct-2010 05:19 PM 
Congestion : Traffic is slow from Prince St to Queen St 

EDIT POUR LA CLARTE

Ces textes très bien formatés, sont effectivement reçus par un e-mail html très mal formaté. Il contient des sauts de ligne aléatoires ici et là, par exemple "Congestion: Trafic \ n est lent de Prince \ nSt à Queen St".

Ainsi, lors du traitement des e-mails, j'enlevai tous les codes html et les sauts de ligne au hasard, et json_encode() eux dans une très longue chaîne unique en ligne sans saut de ligne ...

+0

Je suis confus - pourriez-vous s'il vous plaît montrer votre sortie/match (s) désiré? – jensgram

+0

Je voudrais extraire les mots après 'Congestions:', c'est-à-dire les conditions de circulation de chaque autoroute. – blacklotus

Répondre

2

Vous pouvez essayer un match minimum:

Congestion\s*:\s*(?P<congestion>.*?)

Cela entraînerait le retour zéro caractères dans le groupe nommé « congestion » à moins que vous pourriez correspondre à quelque chose immédiatement après la chaîne de congestion.

Ainsi, cela pourrait être fixé si « la route » commence toujours les dossiers de l'état de la circulation:

Congestion\s*:\s*(?P<congestion>.*?)Highway\s*:

Si cela fonctionne (je ne l'ai pas vérifié), les premiers enregistrements sont adaptés, mais la dernière l'enregistrement n'est pas! Cela pourrait être facilement corrigé en ajoutant le texte 'Highway:' à la fin de la chaîne d'entrée.

+0

Merci beaucoup! :) Cela marche. Je comprends que. * Correspondrait à plusieurs ou à n'importe quoi, mais que faire? faire quand ajouté dans le mélange? – blacklotus

+2

Le point d'interrogation (?) Après un quantificateur (*, +,?, {N, m}) force une correspondance minimale, par exemple si la regex (test) + correspond une fois à la chaîne testtesttesttest, la regex (test) +? correspondrait à quatre fois. –

2
Congestion\s*:\s*Traffic is\s*(?P<c1>[^\n]*)\s*from\s*(?P<c2>[^\n]*)\s*to\s*(?P<c3>[^\n]*)$ 
+0

Cela ne fonctionne malheureusement pas. (? P . *) Correspondrait déjà jusqu'à la fin de la 3ème instance, pour le premier match. – blacklotus

+1

@blacklotus Le point ne doit pas correspondre aux nouvelles lignes, sauf si spécifié avec le drapeau DOTALL. De toute façon, remplacez '.' par' [^ \ n] ' – Amarghosh

+0

Ils sont en fait tous sur une seule ligne, c'est pourquoi. Je devais les mettre en forme bien ici sinon vous ne seriez pas capable de voir le motif. – blacklotus

4

Habituellement, la correspondance regex est basée sur une ligne. Regex suppose que votre chaîne est une seule ligne. Vous pouvez utiliser le m” (PCRE_MULTILINE) flag pour modifier ce comportement. Ensuite, vous pouvez dire à PHP pour correspondre uniquement à la fin de la ligne:

preg_match('/^Congestion\s*:\s*(?P<congestion>.*)$/m', $subject, $matches); 

Il y a deux choses à noter: d'abord, le modèle a été modifié pour inclure la ligne-begin (^) et de fin de ligne ($) Marqueurs. Deuxièmement, le modèle porte maintenant le modificateur m.

+0

+1 Ceci a rendu la question logique :) – jensgram

+0

Ils ne sont pas réellement multilignes. Ils sont en fait un énorme bloc de texte au hasard, que j'ai utilisé json_encode() pour former une chaîne à une seule ligne. J'ai dû les mettre en forme bien ici, sinon ce serait encore plus confus à ma question. – blacklotus

+0

@blacklotus: Dommage. Juste pour vérifier, cependant: d'où avez-vous obtenu le texte. Le codage JSON ne devrait pas jouer avec le formatage de la chaîne (une fois correctement décodé). –