web-dev-qa-db-fra.com

Qu'est-ce qu'un "regex de chaîne brute" et comment pouvez-vous l'utiliser?

De la documentation python sur regex , concernant le '\' personnage:

La solution consiste à utiliser la notation de chaîne brute de Python pour les modèles d’expression régulière; les barres obliques inverses ne sont pas gérées de manière particulière dans un littéral de chaîne préfixé avec 'r'. Donc r"\n" est une chaîne de deux caractères contenant '\' et 'n', tandis que "\n" est une chaîne à un caractère contenant une nouvelle ligne. Habituellement, les motifs seront exprimés en Python utilisant cette notation de chaîne brute.

Quelle est cette notation de chaîne brute? Si vous utilisez un format de chaîne brut, cela signifie-t-il que "*" est pris comme un caractère littéral plutôt que comme un indicateur zéro ou plus? Cela ne peut évidemment pas être vrai, sinon regex perdrait complètement son pouvoir. Mais si c'est une chaîne brute, comment reconnaît-elle les caractères de nouvelle ligne si "\n" est littéralement une barre oblique inverse et un "n"?

Je ne suis pas.

Modifier pour la prime:

J'essaie de comprendre comment une expression rationnelle de chaîne brute correspond à des nouvelles lignes, des tabulations et des jeux de caractères, par exemple \w pour les mots ou \d pour les chiffres ou tout le reste, si les modèles de chaînes brutes ne reconnaissent pas les barres obliques inverses comme autre chose que des caractères ordinaires. Je pourrais vraiment utiliser de bons exemples.

51

La réponse de Zarkonnen répond à votre question, mais pas directement. Permettez-moi d'essayer d'être plus direct et de voir si je peux récupérer la prime de Zarkonnen.

Vous trouverez peut-être cela plus facile à comprendre si vous cessez d'utiliser les termes "expression régulière de chaîne brute" et "modèles de chaîne brute". Ces termes confondent deux concepts distincts: les représentations d'une chaîne particulière dans Python code source, et quelle expression régulière cette chaîne représente.

En fait, il est utile de les considérer comme deux langages de programmation différents, chacun avec sa propre syntaxe. Le langage Python possède un code source qui, entre autres choses, crée des chaînes avec certains contenus et appelle le système d'expression régulière. Le système d'expression régulière possède un code source qui réside dans des objets chaîne et correspond à des chaînes. Les deux langues utilisent la barre oblique inverse comme caractère d'échappement.

Tout d'abord, comprenez qu'une chaîne est une séquence de caractères (c'est-à-dire des octets ou des points de code Unicode; la distinction n'a pas beaucoup d'importance ici). Il existe de nombreuses façons de représenter une chaîne dans Python. Une chaîne brute est simplement l'une de ces représentations. Si deux représentations produisent la même séquence de caractères, elles produisent un comportement équivalent.

Imaginez une chaîne de 2 caractères, composée du caractère barre oblique inverse suivi du caractère n. Si vous savez que la valeur de caractère pour barre oblique inverse est 92, et pour n est 110, alors cette expression génère notre chaîne:

s = chr(92)+chr(110)
print len(s), s

2 \n

La notation de chaîne conventionnelle Python "\n" Ne génère pas cette chaîne. Au lieu de cela, elle génère une chaîne d'un caractère avec un caractère de nouvelle ligne. Le Documents Python 2.4.1. Littéraux de chaîne dites, "Le caractère barre oblique inverse (\) est utilisé pour échapper les caractères qui ont autrement une signification spéciale, comme la nouvelle ligne, la barre oblique inverse elle-même ou le caractère de citation."

s = "\n"
print len(s), s

1 
 

(Notez que la nouvelle ligne n'est pas visible dans cet exemple, mais si vous regardez attentivement, vous verrez une ligne vierge après le "1".)

Pour obtenir notre chaîne à deux caractères, nous devons utiliser un autre caractère - barre oblique inverse pour échapper à la signification spéciale du caractère - barre oblique inverse d'origine:

s = "\\n"
print len(s), s

2 \n

Que faire si vous voulez représenter des chaînes contenant de nombreux caractères - barre oblique inversée? Documents Python 2.4.1. Littéraux de chaîne continuez, "Les littéraux de chaîne peuvent éventuellement être préfixés par une lettre 'r' ou 'R'; ces chaînes sont appelées raw strings et utiliser différentes règles pour interpréter les séquences d'échappement antislash. " Voici notre chaîne à deux caractères, utilisant une représentation de chaîne brute:

s = r"\n"
print len(s), s

2 \n

Nous avons donc trois représentations de chaînes différentes, toutes donnant la même chaîne ou séquence de caractères:

print chr(92)+chr(110) == "\\n" == r"\n"
True

Passons maintenant aux expressions régulières. Documents Python, 7.2. re - Opérations d'expressions régulières dit, "Les expressions régulières utilisent le caractère barre oblique inverse ('\') pour indiquer des formes spéciales ou pour permettre l'utilisation de caractères spéciaux sans invoquer leur signification spéciale. Cela entre en collision avec l'utilisation par Python du même caractère dans le même but dans les littéraux de chaîne ... "

Si vous voulez un Python objet d'expression régulière qui correspond à un caractère de nouvelle ligne, alors vous avez besoin d'une chaîne de 2 caractères, composée du caractère - barre oblique inverse suivi du caractère = n caractère. Les lignes de code suivantes définissent toutes prog sur un objet d'expression régulière qui reconnaît un caractère de nouvelle ligne:

prog = re.compile(chr(92)+chr(110))
prog = re.compile("\\n")
prog = re.compile(r"\n")

Alors pourquoi est-ce que "Habituellement, les modèles seront exprimés en Python utilisant cette notation de chaîne brute." ? Parce que les expressions régulières sont souvent des chaînes statiques, qui sont commodément représentées en tant que littéraux de chaîne. Et parmi les différentes notations de littéraux de chaîne disponibles, les chaînes brutes sont un choix pratique, lorsque l'expression régulière inclut un caractère - barre oblique inverse.

Questions

[~ # ~] q [~ # ~] : qu'en est-il de l'expression re.compile(r"\s\tWord")? [~ # ~] a [~ # ~] : Il est plus facile à comprendre en séparant la chaîne de la compilation d'expressions régulières et en les comprenant séparément.

s = r"\s\tWord"
prog = re.compile(s)

La chaîne s contient huit caractères: a barre oblique inverse, an s, a barre oblique inverse, a = t, puis quatre caractères Word.

[~ # ~] q [~ # ~] : qu'arrive-t-il aux tabulations et espaces? [~ # ~] a [~ # ~] : Au niveau de la langue Python, chaîne s n'a pas de caractère tab et espace. Il commence par quatre caractères: barre oblique inverse, s, barre oblique inverse, t. Le système d'expression régulière, quant à lui, traite cette chaîne comme du code source dans le langage d'expression régulière, où cela signifie "correspond à une chaîne composée d'un caractère d'espacement, d'un caractère de tabulation et des quatre caractères Word.

[~ # ~] q [~ # ~] : Comment faites-vous la correspondance avec ceux-ci si cela est traité comme backlash-s et backslash-t? [~ # ~] a [~ # ~] : Peut-être que la question est plus claire si les mots "vous" et "cela" sont plus précis: comment le système d'expression régulière correspond-il aux expressions backlash-s et backslash-t? Comme 'n'importe quel caractère d'espacement' et comme ' tab caractère'.

[~ # ~] q [~ # ~] : Ou si vous avez la chaîne de 3 caractères backslash-n-newline? [~ # ~] a [~ # ~] : Dans la langue Python, la barre oblique inverse à 3 caractères -n-newline peut être représenté comme une chaîne conventionnelle "\\n\n", ou une chaîne brute plus une chaîne conventionnelle r"\n" "\n", ou par d'autres moyens. Le système d'expression régulière correspond à la chaîne de 3 caractères backslash-n-newline lorsque il trouve deux - nouvelle ligne caractères consécutifs.

N.B. Tous les exemples et références de document sont à Python 2.7.

Mise à jour : clarifications intégrées des réponses de @Vladislav Zorov et @ m.buettner, et de la question de suivi de @Aerovistae.

71
Jim DeLaHunt

La plupart de ces questions contiennent beaucoup de mots et il est peut-être difficile de trouver la réponse à votre question spécifique.

Si vous utilisez une chaîne régulière et que vous transmettez un modèle comme "\ t" à l'analyseur RegEx, Python traduira ce littéral dans un tampon contenant l'octet tab (0x09).

Si vous utilisez une chaîne brute et que vous passez un modèle comme r "\ t" à l'analyseur RegEx, Python ne fait aucune interprétation et crée un tampon de deux octets: '\' et 't'. (0x5c, 0x74).

L'analyseur RegEx sait quoi faire avec la séquence "\ t" - il compare cela à un onglet. Il sait également quoi faire avec le caractère 0x09 - qui correspond également à un onglet. Pour la plupart, les résultats seront indiscernables.

La clé pour comprendre ce qui se passe est donc de reconnaître que deux analyseurs sont employés ici. Le premier est l'analyseur Python, et il traduit votre littéral de chaîne (ou littéral de chaîne brut) en une séquence d'octets. Le second est l'analyseur d'expressions régulières de Python, et il convertit une séquence de octets dans une expression régulière compilée.

14
Geoff Gerrietts

Le problème avec l'utilisation d'une chaîne normale pour écrire des expressions rationnelles qui contiennent un \ c'est que vous devez écrire \\ pour chaque \. Ainsi, les littéraux de chaîne "stuff\\things" et r"stuff\things" produit la même chaîne. Cela devient particulièrement utile si vous souhaitez écrire une expression régulière qui correspond aux contre-obliques.

En utilisant des chaînes normales, une expression rationnelle qui correspond à la chaîne \ serait "\\\\"!

Pourquoi? Parce que nous devons échapper \ deux fois: une fois pour la syntaxe d'expression régulière et une fois pour la syntaxe de chaîne.

Vous pouvez utiliser des guillemets triples pour inclure des retours à la ligne, comme ceci:

r'''stuff\
things'''

Notez qu'en général, python traiterait \- newline comme suite de ligne, mais ce n'est pas le cas dans les chaînes brutes. Notez également que les barres obliques inverses échappent toujours aux guillemets dans les chaînes brutes, mais sont laissées en elles-mêmes. Ainsi, la chaîne brute littérale r"\"" produit la chaîne \". Cela signifie que vous ne pouvez pas terminer un littéral de chaîne brut avec une barre oblique inverse.

Voir la section d'analyse lexicale de la Python pour plus d'informations.

5
Zarkonnen

Vous semblez avoir du mal avec l'idée qu'un RegEx ne fait pas partie de Python, mais plutôt un langage de programmation différent avec son propre analyseur et compilateur. Les chaînes brutes vous aident à obtenir le "code source" d'un RegEx en toute sécurité à l'analyseur RegEx, qui attribuera ensuite une signification aux séquences de caractères comme \d, \w, \n, etc...

Le problème existe parce que Python et RegExps utilisent \ comme caractère d'échappement, ce qui est d'ailleurs une coïncidence - il existe des langues avec d'autres caractères d'échappement (comme "` n "pour une nouvelle ligne, mais même là, vous devez utiliser"\n "dans RegExps). L'avantage est que vous n'avez pas besoin de faire la différence entre les chaînes brutes et non brutes dans ces langues, ils n'essaieront pas à la fois de convertir le texte et de le massacrer, car ils réagissent à différentes séquences d'échappement.

4
Vladislav Zorov

La section du manuel Python ("Littéraux de chaîne et octets") a une explication claire des littéraux de chaîne bruts:

Les littéraux de chaîne et d'octets peuvent éventuellement être préfixés par une lettre "r" ou "R"; ces chaînes sont appelées chaînes brutes et traitent les barres obliques inverses comme des caractères littéraux. Par conséquent, dans les littéraux de chaîne, les échappements "\ U" et "\ u" dans les chaînes brutes ne sont pas traités spécialement. Étant donné que Python 2.x les littéraux unicode bruts se comportent différemment de Python 3.x) la syntaxe 'ur' n'est pas prise en charge.

Nouveau dans la version 3.3: le préfixe "rb" des littéraux d'octets bruts a été ajouté comme synonyme de "br".

Nouveau dans la version 3.3: la prise en charge du littéral hérité unicode (u'value ') a été réintroduite pour simplifier la maintenance des bases de code dual Python 2.x et 3.x. Voir PEP 414 pour plus d'informations .

Dans les chaînes entre guillemets triples, les retours à la ligne et les guillemets sans échappement sont autorisés (et sont conservés), sauf que trois guillemets sans échappement dans une ligne terminent la chaîne. (Une "citation" est le caractère utilisé pour ouvrir la chaîne, c'est-à-dire 'ou ".)

À moins qu'un préfixe "r" ou "R" ne soit présent, les séquences d'échappement dans les chaînes sont interprétées selon des règles similaires à celles utilisées par la norme C. Les séquences d'échappement reconnues sont:

Séquence d'échappement Signification Notes

\ newline Backslash et newline ignorés
\Barre oblique inverse ()
\' Simple citation (')
\" Double citation (")
\a ASCII Bell (BEL)
\b ASCII Retour arrière (BS)
\f ASCII Alimentation (FF)
\n ASCII Saut de ligne (LF)
\r ASCII Retour chariot (CR)
\t ASCII Onglet horizontal (TAB)\v ASCII Onglet vertical (VT)
\ooo Caractère avec une valeur octale ooo (1,3)
\xhh Caractère avec valeur hexadécimale hh (2,3)

Les séquences d'échappement reconnues uniquement dans les littéraux de chaîne sont:

Séquence d'échappement Signification Notes\N {nom} Caractère nommé nom dans la base de données Unicode (4)\uxxxx Caractère avec une valeur hexadécimale 16 bits xxxx (5)\Uxxxxxxxx Caractère avec une valeur hexadécimale 32 bits xxxxxxxx (6)

Remarques:

  1. Comme dans la norme C, jusqu'à trois chiffres octaux sont acceptés.

  2. Contrairement à la norme C, exactement deux chiffres hexadécimaux sont requis.

  3. Dans un octet littéral, les échappements hexadécimaux et octaux désignent l'octet avec la valeur donnée. Dans un littéral de chaîne, ces échappements indiquent un caractère Unicode avec la valeur donnée.

  4. Modifié dans la version 3.3: la prise en charge des alias de nom [1] a été ajoutée.

  5. Les unités de code individuelles qui font partie d'une paire de substitution peuvent être codées à l'aide de cette séquence d'échappement. Exactement quatre chiffres hexadécimaux sont requis.

  6. Tout caractère Unicode peut être codé de cette façon, mais les caractères en dehors du plan multilingue de base (BMP) seront codés à l'aide d'une paire de substitution si Python est compilé pour utiliser des unités de code 16 bits (par défaut) . Exactement huit chiffres hexadécimaux sont requis.

Contrairement à la norme C, toutes les séquences d'échappement non reconnues sont laissées inchangées dans la chaîne, c'est-à-dire que la barre oblique inverse est laissée dans la chaîne. (Ce comportement est utile lors du débogage: si une séquence d'échappement est mal typée, la sortie résultante est plus facilement reconnue comme rompue.) Il est également important de noter que les séquences d'échappement reconnues uniquement dans les littéraux de chaîne entrent dans la catégorie des échappements non reconnus pour les octets. littéraux.

Même dans une chaîne brute, les guillemets de chaîne peuvent être échappés avec une barre oblique inverse, mais la barre oblique inverse reste dans la chaîne; par exemple, r "\" "est un littéral de chaîne valide composé de deux caractères: une barre oblique inverse et un guillemet double; r"\"n'est pas un littéral de chaîne valide (même une chaîne brute ne peut pas se terminer par un nombre impair de barres obliques inverses). Plus précisément, une chaîne brute ne peut pas se terminer par une seule barre oblique inverse (car la barre oblique inverse échapperait au caractère de guillemet suivant). Notez également qu'une barre oblique inverse simple suivie d'une nouvelle ligne est interprétée comme ces deux caractères comme faisant partie de la chaîne, et non comme une continuation de ligne .

1
Lorenzo Gatti