J'ai une question. Comment vérifier si une chaîne python contient des caractères qui ne sont pas dans une liste donnée?
Voici la liste (ensemble):
set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._")
4 Réponses :
any pour enregistrer SET pour chaque caractère de chaîne SET = set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._")
s = "123#"
print(any(x not in SET for x in s))
pourquoi pas simplement set (s) - SET ?
Vous avez juste besoin de savoir si votre chaîne contient des caractères qui ne sont pas en S. L'utilisation de any peut aider à arrêter prématurément.
@thebjorn Dépend de la chaîne. Votre chemin construit toujours l'ensemble complet tandis que any s'arrête au premier non-membre. Le vôtre est donc plus lent par exemple pour s = "# 123456789" . Peut-être que SET.issuperset (s) est le meilleur.
@HeapOverflow cela ne dépend pas vraiment de la chaîne, les seuls cas dégénérés sont lorsque le caractère illégal est dans les trois premières positions d'une longue chaîne. Si l'une de ces conditions n'est pas remplie, par ex. si la chaîne est courte: set ("# 12") - SET est environ 25% plus rapide que la version any . L'implémentation d'ensemble a également un temps d'exécution prévisible puisqu'elle est implémentée en C alors que la boucle any est en Python - sans oublier que la version set est beaucoup plus facile à comprendre.
@thebjorn Pas vrai. Pour s = '123 #' * 1000 , le caractère illégal n'est pas dans les trois premières positions et la solution any est environ 65 fois plus rapide que la vôtre. Fait intéressant, la solution issuperset est à peu près aussi lente que la vôtre, donc apparemment, elle ne fonctionne pas paresseusement. C'est une déception surprenante.
@HeapOverflow ennuyeusement vous avez raison ;-) Voir ma réponse pour les comparaisons (regex semble être le meilleur ..) - bah, il a été fermé avant que je puisse poster ma réponse, mais le plus rapide était re.compile (r "[^ -._ \ w \ d]")
@thebjorn Cela semble en effet être le plus rapide. Peut également utiliser r "[^ -. \ W]" , car \ w comprend des chiffres et des traits de soulignement.
Je m'en remets toujours aux expressions régulières lors de la validation de chaînes.
Pour créer un ensemble, vous placez tous les caractères de l'ensemble dans [] .
Pour vérifier si une chaîne contient un caractère pas dans un ensemble, ajoutez ^ au début.
Pour vérifier si la chaîne contient un ou plusieurs membres d'un ensemble, ajoutez + .
Compte tenu de ces informations, une expression régulière pour vérifier si une chaîne contient des caractères autres que {a, b, c, d} ressemblerait à ceci:
[^ abcd] + (notez que ceci est sensible à la casse)
Pour utiliser des expressions régulières en python, import re . La méthode re.search (pattern, string, flags = 0) recherchera dans toute la chaîne le modèle que vous donnez.
Pour plus d'informations sur les expressions régulières en python, cliquez ici . Un testeur d'expressions régulières simple est disponible ici .
Vous souhaitez tester si les caractères de la chaîne ne sont pas un sous-ensemble du jeu de caractères donné. C'est simple en Python car l'opérateur Exemples: teste si un ensemble est un sous-ensemble d'un autre. >>> uses_other_chars('abc')
False
>>> uses_other_chars('Hello!')
True
import string
# don't use a mutable set for this purpose
GIVEN = frozenset(string.ascii_letters + string.digits + '-._')
def uses_other_chars(s, given=GIVEN):
return not set(s) <= given
Il y a aussi set.issuperset , qui prend tout itérable.
Ça ne fait rien. Je pensais que ce serait plus rapide car cela pourrait s'arrêter au premier non-membre au lieu de créer d'abord un ensemble de tous les s , mais je viens de vérifier et le fait quand même . Gah.
En comparant le runtime des différentes solutions:
r.search(s)
"#12" 0.470
"#1234567" 0.514
"1234567#" 0.572
"123" * 100 + "#" 3.493
"123#" * 100 0.502
set(s) - SET
"#12" 0.566
"#1234567" 1.045
"1234567#" 1.075
"123" * 100 + "#" 7.658
"123#" * 100 10.170
any(x not in SET for x in s)
"#12" 0.786
"#1234567" 0.797
"1234567#" 1.475
"123" * 100 + "#" 27.266
"123#" * 100 1.087
SET.issuperset(s)
"#12" 0.466
"#1234567" 0.864
"1234567#" 0.896
"123" * 100 + "#" 7.512
"123#" * 100 10.199
qui donne la sortie suivante sur ma machine:
import timeit
search_strings = [
'"#12"', # short string, early match
'"#1234567"', # longer string, early match
'"1234567#"', # longer string, late match
'"123" * 100 + "#"', # long string, late match
'"123#" * 100', # long string early match
]
algorithms = [
("r.search(s)", 's={};import re; r = re.compile(r"[^-.\w]")'),
("set(s) - SET", 's={};SET=frozenset("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._")'),
("any(x not in SET for x in s)", 's={};SET=frozenset("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._")'),
("SET.issuperset(s)", 's={};SET=frozenset("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._")'),
]
for alg, setup in algorithms:
print alg
for sstr in search_strings:
print "%35s %.3f" % (sstr[:35], timeit.timeit(alg, setup.format(sstr)))
on voit que le La solution regex est la plus rapide.
Convertissez la chaîne en un
ensemble, puis obtenez la différence entre les deux ensembles. Si ce n'est pas vide, la chaîne contient des caractères qui ne font pas partie de l'ensemble.pourquoi cela a-t-il été fermé avec raison «mettre à jour la question pour qu'elle se concentre sur un seul problème»? Où est le deuxième problème? La question est clairement claire comme le montrent les réponses. Veuillez rouvrir.