web-dev-qa-db-fra.com

Python re.sub (): comment substituer tous les 'u' ou 'U' par 'you'

Je suis en train de normaliser le texte à l'aide de python et d'expressions régulières. J'aimerais remplacer tous les "u" ou "U" par "vous". Voici ce que j'ai fait jusqu'à présent:

import re
text = 'how are u? umberella u! u. U. U@ U# u '
print re.sub (' [u|U][s,.,?,!,W,#,@ (^a-zA-Z)]', ' you ', text)

Le résultat obtenu est:

how are you  you berella you  you  you  you  you  you

Comme vous pouvez le constater, le problème est que "umberella" est remplacé par "berella". Aussi, je veux garder le caractère qui apparaît après un "u". Par exemple, je veux 'u!' être changé en 'vous!' Quelqu'un peut-il me dire ce que je fais mal et quelle est la meilleure façon d'écrire l'expression régulière?

43
user823743

Premièrement, pourquoi votre solution ne fonctionne-t-elle pas? Vous mélangez beaucoup de concepts. Généralement classe de personnage avec d'autres. Dans la première classe de caractères, vous utilisez | qui provient de alternance . Dans les classes de caractères, vous n'avez pas besoin du tuyau. Il suffit de lister tous les caractères (et plages de caractères) que vous voulez:

[Uu]

Ou simplement écrivez u si vous utilisez le modificateur insensible à la casse. Si vous écrivez un pipe là-bas, la classe de caractères correspondra aux pipes de votre chaîne de sujet.

Maintenant, dans la deuxième classe de caractères, vous utilisez la virgule pour séparer vos caractères pour une raison quelconque. Cela ne fait rien d'autre que d'inclure des virgules dans les caractères interchangeables. s et W sont probablement supposés être les classes de caractères intégrées. Alors leur échapper! Sinon, ils ne feront que correspondre au littéral s et au littéral W. Mais alors \W inclut déjà tout ce que vous avez énuméré, donc un \W seul (sans crochets) aurait suffi. Et la dernière partie (^a-zA-Z) _ ne fonctionne pas non plus, car il inclura simplement ^, (, ) et toutes les lettres dans la classe de caractères. La syntaxe de négation ne fonctionne que pour des classes de caractères entières comme [^a-zA-Z].

Ce que vous voulez réellement est d’affirmer qu’il n’ya pas de lettre devant ou après votre u. Vous pouvez utiliser lookarounds pour cela. L'avantage est qu'ils ne seront pas inclus dans le match et ne seront donc pas supprimés:

r'(?<![a-zA-Z])[uU](?![a-zA-Z])'

Notez que j'ai utilisé une chaîne brute. C'est généralement une bonne pratique pour les expressions régulières, pour éviter les problèmes de séquences d'échappement.

Ce sont des comparaisons négatives qui s'assurent qu'il n'y a pas de caractère de lettre avant ou après votre u. C'est une différence importante pour affirmer qu'il y a un caractère non-lettre autour (ce qui est similaire à ce que vous avez fait), car cette dernière approche ne fonctionnera pas au début ou à la fin de la chaîne.

Bien sûr, vous pouvez supprimer les espaces autour de you de la chaîne de remplacement.

Si vous ne voulez pas remplacer u à côté de chiffres, vous pouvez facilement inclure les chiffres dans les classes de caractères:

r'(?<![a-zA-Z0-9])[uU](?![a-zA-Z0-9])'

Et si pour une raison quelconque, un trait de soulignement adjacent disqualifiait également votre u au remplacement, vous pouvez également l'inclure. Mais alors la classe de caractères coïncide avec le \w:

r'(?<!\w)[uU](?!\w)'

Ce qui, dans ce cas, équivaut à EarlGray's r'\b[uU]\b'.

Comme mentionné ci-dessus, vous pouvez les raccourcir en utilisant le modificateur insensible à la casse. Prenant la première expression comme exemple:

re.sub(r'(?<![a-z])u(?![a-z])', 'you', text, flags=re.I)

ou

re.sub(r'(?<![a-z])u(?![a-z])', 'you', text, flags=re.IGNORECASE)

selon vos préférences.

Je vous suggère de lire le tutoriel que j'ai lié plusieurs fois dans cette réponse. Les explications sont très complètes et devraient vous donner une bonne longueur d’avance sur les expressions régulières, que vous rencontrerez probablement tôt ou tard.

64
Martin Ender

Utilisez un caractère spécial \b, qui correspond à une chaîne vide au début ou à la fin d'un mot:

print re.sub(r'\b[uU]\b', 'you', text)

les espaces ne sont pas une solution fiable, car il y a aussi beaucoup d'autres signes de ponctuation, donc un caractère abstrait \b a été inventé pour indiquer le début ou la fin d'un mot.

13
Dmytro Sirenko

Cela a fonctionné pour moi:

    import re
    text = 'how are u? umberella u! u. U. U@ U# u '
    rex = re.compile(r'\bu\b', re.IGNORECASE)
    print(rex.sub('you', text))

Il pré-compile l'expression régulière et utilise re.IGNORECASE afin que nous n'ayons pas à nous soucier de la casse dans notre expression régulière! BTW, j'aime l'orthographe géniale de parapluie! :-)

3
ricdeez

il peut également être réalisé avec le code ci-dessous

import re

text = 'how are u? umberella u! u. U. U@ U# u '
print (re.sub (r'[uU] ( [^a-z] )', r' you\1 ', text))

ou

print (re.sub (r'[uU] ( [\s!,.?@#] )', r' you\1 ', text))
2
Jagadanna

Une autre solution possible que j'ai trouvée était:

re.sub(r'([uU]+(.)?\s)',' you ', text)
1
Edward