36 votes

Incohérence entre $ et ^ dans une regex lors de l'utilisation d'arguments début / fin pour effectuer une nouvelle recherche?

De ce que j'ai lu, ^ doit correspondre au début d'une chaîne, et $ à la fin. Cependant, avec re.search(), il semble que le comportement de l' ^ continue à travailler très bien, tandis que $ "pauses". Exemple:

>>> a = re.compile( "^a" )
>>> print a.search( "cat", 1, 3 )
None

Cela semble correct pour moi -- 'a' n'est pas au début de la chaîne, même si c'est au début de la recherche.

>>> a = re.compile( "a$" )
>>> print a.search( "cat", 0, 2 )
<_sre.SRE_Match object at 0x7f41df2334a8>

Cela semble mauvais pour moi, ou en contradiction, au moins.

La documentation sur l' re module mentionne explicitement que le comportement de l' ^ ne change pas en raison de début/fin arguments au re.search, mais aucun changement de comportement est mentionné pour $ (que j'ai vu).

Quelqu'un peut-il expliquer pourquoi les choses ont été conçues de cette manière, et/ou proposer une solution pratique?

Par la solution de contournement, je souhaite composer une expression régulière qui correspond toujours à la fin de la chaîne, même quand quelqu'un utilise la fin argument re.search.

Et pourquoi était - re.search conçu de telle sorte que:

s.search( string, endPos=len(string) - 1 )

est le même que

s.search( string[:-1] )

lorsque

s.search( string, startPos=1 )

est explicitement et intentionnellement pas le même que

s.search( string[1:] )

Il semble être moins un problème d'incompatibilité entre ^ et $, et plus d'une incohérence dans l' re.search fonction.

28voto

Greg Anders Points 910

Selon la search() documentation ici:

Le paramètre facultatif endpos limites dans quelle mesure la chaîne sera recherché; ce sera comme si la chaîne est endpos caractères de long, de sorte que les caractères de pos à endpos - 1 sera recherché pour un match.

Donc, votre syntaxe, a.search("cat", 0, 2) est équivalent à a.search("ca"), ce qui correspond à la répétition a$.

21voto

cdlane Points 2604

Cela semble mauvais pour moi, ou en contradiction, au moins.

Non, l' endpos interprétation est cohérente avec le reste de Python, c'est le départ pos position qui n'est pas cohérent que la documentation explique:

le paramètre pos donne un indice dans la chaîne où la recherche est démarrer; la valeur par défaut est 0. Ce n'est pas tout à fait équivalents à découpage la chaîne; le '^' modèle de caractère correspond à la véritable début de la chaîne

21voto

Kevin J. Chase Points 2988

Réponse Courte

Utiliser \A et \Z pour correspondre à la traduction littérale début ou à la fin d'une chaîne. Les lignes de l' re du module docs:

6.2.1. La Syntaxe D'Expression Régulière

\A Ne correspond qu'au début de la chaîne.

\Z Ne correspond qu'à la fin de la chaîne.

Mise en garde à propos de endpos

Ce ne sera pas de travail ", même quand quelqu'un utilise la fin argument re.search". Contrairement à la "start" paramètre pos, qui marque un point de départ, l' endpos paramètre signifie que la recherche (ou du match), sera réalisé sur une portion seulement de la chaîne (italiques ajoutés):

6.2.3. Expression Régulière Objets

regex.search(string[, pos[, endpos]])

Le paramètre facultatif endpos limites dans quelle mesure la chaîne sera recherché; ce sera comme si la chaîne est - endpos caractères, [...] rx.search(string, 0, 50) est équivalent à rx.search(string[:50], 0).

L' \Z correspond à la fin de la chaîne de recherche en cours, ce qui est exactement ce endpos changements.

Arrière-plan

La plus familière ^ et $ ne font pas ce que vous pensez qu'ils font:

^ (Accent circonflexe.) Correspond au début de la chaîne, et, en MULTILINE mode correspond également immédiatement après chaque retour à la ligne.

$ Correspond à la fin de la chaîne ou juste avant le saut de ligne à la fin de la chaîne, et, en MULTILINE mode correspond également à la avant un retour à la ligne. foo correspond à la fois à " foo " et "foobar", tandis que l'expression régulière foo$ correspond uniquement 'foo'. Plus intéressant, la recherche d' foo.$ en 'foo1\nfoo2\n' des matchs foo2 "normalement, mais "toto1" en MULTILINEmode; la recherche d'une seule $ en 'foo\n' trouverez deux (vide) correspond à: juste avant le saut de ligne, et un à la fin de la chaîne.

Python expressions régulières sont fortement influencés par Perl, qui a étendu le vieux - grep des capacités avec un hôte de son propre. Que multi-ligne correspondant, ce qui pose une question à propos des caractères comme ^: Il a été correspondant au début de la chaîne, ou le début de la ligne? Lors de l' grep a été seulement de correspondance une ligne à la fois, ce furent des concepts équivalents.

Comme vous pouvez le voir, ^ et $ fini d'essayer de faire correspondre tout "start-like" et "fin-ish". Perl a présenté les nouvelles séquences d'échappement \A et \z (en minuscules) pour correspondre seulement le début de la chaîne et de fin de chaîne.

Ces séquences d'échappement ont été adoptées par Python, mais avec une différence: Python ne pas adopter de Perl \Z (en majuscules), qui correspondait à la fois la fin de la chaîne et le cas particulier de saut de ligne avant la fin de la chaîne de... il n'est pas tout à fait le partenaire en \A que l'on pourrait attendre.

(Je suppose Python haut-tubé Perl \z , pour plus de cohérence, en évitant le déséquilibre '\Apattern\z' regexes qui ont été recommandées dans des livres comme Perl Best Practices.)

Histoire de l' pos et endpos

Il semble que l'étrange "pas réellement la start-position de départ" sens de l' pos est aussi vieux que le paramètre lui-même:

  • Le Python de 1,4 match fonction docs (25 Oct 1996 --- probablement pré-datant de l'objet regex) ne montrent pas l' pos ou endpos paramètres à tous.

  • Le Python de 1,5 match méthode docs (17 Février 1998) de présenter à la fois l'expression régulière de l'objet et de l' pos et endposparamètres. Il déclare qu'un ^ va correspondre à l' pos, bien que les révisions ultérieures suggèrent c'était une faute de frappe. (En parlant de fautes de frappe: L' ^ personnage lui-même est manquant. Il est venu et est allé, jusqu'à ce que finalement réapparaître pour de bonnes(?) en Python 2.1.)

  • Le Python 1.5.1 match méthode docs (14 Avril 1998) insérez le manque de "non", l'inversion de la précédente docs.

  • Le Python 1.5.1p1 match méthode docs (06 Août 1998) préciser les des effets inattendus de la pos. Ils correspondent Python 3.6.1 la description de l' posmot-pour-mot... donner ou prendre ce fichus ^ typo.

Je soupçonne que les nombreuses modifications apportées à la documentation sur une couple de mois de bug-fix communiqués de refléter les docs de rattrapage avec la réalité --- pas de modifications à la conception de l' match (bien que je n'ai pas de Python 1 traînent à vérifier).

L' python-dev archives des listes de diffusion seulement revenir à 1999, donc à moins que le plus tôt les messages ont été enregistré quelque part, je pense que répondre au "pourquoi" question nécessiterait de deviner qui a écrit ce code, et de le leur demander.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X