Wie überprüfe ich, dass ein String nur Buchstaben, Zahlen, Unterstriche und Bindestriche enthält?

Ich weiß, wie dies zu tun ist, wenn ich durch alle Charaktere in der Saite iteriere, aber ich bin auf der Suche nach einer eleganteren Methode.

10 Solutions collect form web for “Wie überprüfe ich, dass ein String nur Buchstaben, Zahlen, Unterstriche und Bindestriche enthält?”

Ein regelmäßiger Ausdruck wird den Trick mit sehr wenig Code machen:

import re ... if re.match("^[A-Za-z0-9_-]*$", my_little_string): # do something here 

[Bearbeiten] Es gibt noch eine andere Lösung, die noch nicht erwähnt wird, und es scheint, die anderen in den meisten Fällen so weit zu übertreffen.

Verwenden Sie string.translate, um alle gültigen Zeichen in der Zeichenfolge zu ersetzen, und sehen Sie, ob wir irgendwelche ungültige übrig haben. Das ist ziemlich schnell, da es die zugrundeliegende C-Funktion benutzt, um die Arbeit zu machen, mit sehr wenig python-Bytecode beteiligt.

Offensichtlich ist die Leistung nicht alles – für die meisten lesbaren Lösungen ist wohl der beste Ansatz, wenn nicht in einem leistungskritischen Codepath, sondern nur um zu sehen, wie die Lösungen stapeln, hier ist ein Performance-Vergleich aller bisher vorgeschlagenen Methoden. Check_trans ist die mit der string.translate-Methode.

Testcode:

 import string, re, timeit pat = re.compile('[\w-]*$') pat_inv = re.compile ('[^\w-]') allowed_chars=string.ascii_letters + string.digits + '_-' allowed_set = set(allowed_chars) trans_table = string.maketrans('','') def check_set_diff(s): return not set(s) - allowed_set def check_set_all(s): return all(x in allowed_set for x in s) def check_set_subset(s): return set(s).issubset(allowed_set) def check_re_match(s): return pat.match(s) def check_re_inverse(s): # Search for non-matching character. return not pat_inv.search(s) def check_trans(s): return not s.translate(trans_table,allowed_chars) test_long_almost_valid='a_very_long_string_that_is_mostly_valid_except_for_last_char'*99 + '!' test_long_valid='a_very_long_string_that_is_completely_valid_' * 99 test_short_valid='short_valid_string' test_short_invalid='/$%$%&' test_long_invalid='/$%$%&' * 99 test_empty='' def main(): funcs = sorted(f for f in globals() if f.startswith('check_')) tests = sorted(f for f in globals() if f.startswith('test_')) for test in tests: print "Test %-15s (length = %d):" % (test, len(globals()[test])) for func in funcs: print " %-20s : %.3f" % (func, timeit.Timer('%s(%s)' % (func, test), 'from __main__ import pat,allowed_set,%s' % ','.join(funcs+tests)).timeit(10000)) print if __name__=='__main__': main() 

Die Ergebnisse auf meinem System sind:

 Test test_empty (length = 0): check_re_inverse : 0.042 check_re_match : 0.030 check_set_all : 0.027 check_set_diff : 0.029 check_set_subset : 0.029 check_trans : 0.014 Test test_long_almost_valid (length = 5941): check_re_inverse : 2.690 check_re_match : 3.037 check_set_all : 18.860 check_set_diff : 2.905 check_set_subset : 2.903 check_trans : 0.182 Test test_long_invalid (length = 594): check_re_inverse : 0.017 check_re_match : 0.015 check_set_all : 0.044 check_set_diff : 0.311 check_set_subset : 0.308 check_trans : 0.034 Test test_long_valid (length = 4356): check_re_inverse : 1.890 check_re_match : 1.010 check_set_all : 14.411 check_set_diff : 2.101 check_set_subset : 2.333 check_trans : 0.140 Test test_short_invalid (length = 6): check_re_inverse : 0.017 check_re_match : 0.019 check_set_all : 0.044 check_set_diff : 0.032 check_set_subset : 0.037 check_trans : 0.015 Test test_short_valid (length = 18): check_re_inverse : 0.125 check_re_match : 0.066 check_set_all : 0.104 check_set_diff : 0.051 check_set_subset : 0.046 check_trans : 0.017 

Der Translate-Ansatz scheint in den meisten Fällen am drastischsten zu sein, drastisch so mit langen gültigen Strings, aber wird durch Regexes in test_long_invalid geschlagen (vermutlich weil die Regex sofort ausbessern kann, aber übersetzen muss immer die ganze Saite scannen). Die Set-Ansätze sind meist am schlimmsten und schlagen Regexen nur für den leeren String-Case.

Mit allen (x in allowed_set für x in s) ist es gut, wenn es früh frühstückt, aber kann schlecht sein, wenn es durch jedes Zeichen iterieren muss. IsSubSet und set different sind vergleichbar und sind konsequent proportional zur Länge des Strings unabhängig von den Daten.

Es gibt einen ähnlichen Unterschied zwischen den Regex-Methoden, die alle gültigen Zeichen entsprechen und nach ungültigen Zeichen suchen. Matching führt ein wenig besser aus, wenn man nach einem langen, aber voll gültigen String sucht, aber schlimmer für ungültige Zeichen am Ende des Strings.

Es gibt eine Vielzahl von Möglichkeiten, dieses Ziel zu erreichen, einige sind klarer als andere. Für jedes meiner Beispiele bedeutet 'True', dass der String gültig ist, 'False' bedeutet, dass er ungültige Zeichen enthält.

Zunächst einmal gibt es den naiven Ansatz:

 import string allowed = string.letters + string.digits + '_' + '-' def check_naive(mystring): return all(c in allowed for c in mystring) 

Dann gibt es einen regulären Ausdruck, das kannst du mit re.match () machen. Beachten Sie, dass '-' am Ende des [] sein muss, sonst wird es als 'range' Trennzeichen verwendet. Beachten Sie auch die $ was bedeutet "Ende der Zeichenfolge". Andere Antworten, die in dieser Frage erwähnt werden, verwenden eine spezielle Charakterklasse, '\ w', ich ziehe es immer vor, einen expliziten Zeichenklassenbereich mit [] zu verwenden, weil es einfacher zu verstehen ist, ohne eine kurze Referenzanleitung nachschlagen zu müssen, und einfacher, Fall.

 import re CHECK_RE = re.compile('[a-zA-Z0-9_-]+$') def check_re(mystring): return CHECK_RE.match(mystring) 

Eine andere Lösung stellte fest, dass man eine umgekehrte Übereinstimmung mit regulären Ausdrücken machen kann. Beachten Sie, dass [^ …] die Zeichenklasse invertiert, weil das ^ verwendet wird:

 CHECK_INV_RE = re.compile('[^a-zA-Z0-9_-]') def check_inv_re(mystring): return not CHECK_INV_RE.search(mystring) 

Sie können auch etwas Tricky mit dem 'set' Objekt machen. Werfen Sie einen Blick auf dieses Beispiel, das aus der Original-String alle Zeichen, die erlaubt sind, entfernt, so dass wir mit einem Satz, der entweder a) nichts, oder b) die beleidigenden Zeichen aus der Zeichenfolge:

 def check_set(mystring): return not set(mystring) - set(allowed) 

Wenn es nicht für die Bindestriche und Unterstriche wäre, wäre die einfachste Lösung

 my_little_string.isalnum() 

(Abschnitt 3.6.1 der Python-Bibliotheksreferenz)

Als eine Alternative zur Verwendung von regex können Sie es in Sets:

 from sets import Set allowed_chars = Set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-') if Set(my_little_sting).issubset(allowed_chars): # your action print True 
  pat = re.compile ('[^\w-]') def onlyallowed(s): return not pat.search (s) 

Nun können Sie die Hilfe von Regex fragen, die groß hier drin 🙂

Code:

 import re string = 'adsfg34wrtwe4r2_()' #your string that needs to be matched. regex = r'^[\w\d_()]*$' # you can also add a space in regex if u want to allow it in the string if re.match(regex,string): print 'yes' else: print 'false' 

Ausgabe:

 yes 

Hoffe das hilft 🙂

Sie könnten immer ein Listenverständnis verwenden und die Ergebnisse mit allen überprüfen, es wäre ein wenig weniger ressourcenintensiv als mit einem Regex: all([c in string.letters + string.digits + ["_", "-"] for c in mystring])

Hier ist etwas, das auf Jerubs "naivem Ansatz" basiert (naiv ist seine Worte, nicht meins!):

 import string ALLOWED = frozenset(string.ascii_letters + string.digits + '_' + '-') def check(mystring): return all(c in ALLOWED for c in mystring) 

Wenn ALLOWED war eine String dann denke ich c in ALLOWED würde c in ALLOWED über jedes Zeichen in der Zeichenfolge, bis es ein Spiel gefunden oder erreicht das Ende. Welches, um Joel Spolsky zu zitieren, ist etwas von einem Shlemiel der Maler-Algorithmus .

Aber das Testen auf Existenz in einem Satz sollte effizienter oder zumindest weniger abhängig von der Anzahl der erlaubten Zeichen sein. Sicherlich ist dieser Ansatz ein bisschen schneller auf meiner Maschine. Es ist klar und ich denke, es macht viel gut genug für die meisten Fälle (auf meiner langsamen Maschine kann ich Zehntausende von kurz-ish Strings in einem Bruchteil einer Sekunde validieren). Ich mag das.

AKTUELL auf meiner Maschine arbeitet ein Regexp mehrmals schneller und ist genauso einfach wie dieser (wohl einfacher). So ist das wohl der beste Weg nach vorne.

Verwenden Sie eine Regex und sehen, ob es passt!

 ([az][AZ][0-9]\_\-)* 
  • Finde heraus, die Worte erschienen in einem Absatz
  • Wie man bitweise exklusiv oder von zwei strings in python macht?
  • Unicode, reguläre Ausdrücke und PyPy
  • Aufteilen eines Semikolons getrennten Strings in ein Wörterbuch in Python
  • Rekursive Umsetzung von Permutationen in Python
  • Finde Start- und Endpositionen aller Vorkommnisse innerhalb eines Strings in Python
  • Extrahieren von Wörtern aus einer Zeichenfolge, Entfernen von Interpunktion und Zurückgeben einer Liste mit getrennten Wörtern in Python
  • Bequemer Weg, um lange SQL-Anweisungen in Javascript zu verpacken
  • Python-String mit Platz und ohne Platz am Ende und Unveränderlichkeit
  • Python json dump schreibbarkeit "not write able"
  • Wie kann ich Wildcards in benutzerdefinierten Suchzeichenfolgen in Python unterstützen?
  • Python ist die beste Programmiersprache der Welt.