Sie könnten das vereinfachen, um: ^ [\ w \ d _-] * $
Prestaul
13
Diese Lösung passt zu Zeichenfolgen mit einer Länge von Null. Verwenden Sie + anstelle von *, damit Zeichenfolgen mit 1 oder mehr Zeichen übereinstimmen.
Korrektur: isvalid = re.match(r'[\w-]*$', astr)- Leere Zeichenfolgen sind gültig.
JFS
Wie können Sie auch einen Punkt / Punkt (.) In dieser Regex zulassen? Bearbeiten, hier ist wie: ^ [a-zA-Z0-9 -_ \ s \.] + $
fredrik
23
[Bearbeiten] Es gibt eine andere Lösung, die noch nicht erwähnt wurde, und sie scheint in den meisten Fällen die anderen bisherigen zu übertreffen.
Verwenden Sie string.translate, um alle gültigen Zeichen in der Zeichenfolge zu ersetzen, und prüfen Sie, ob noch ungültige Zeichen übrig sind. Dies ist ziemlich schnell, da die zugrunde liegende C-Funktion für die Arbeit verwendet wird und nur sehr wenig Python-Bytecode erforderlich ist.
Offensichtlich ist Leistung nicht alles - die Suche nach den am besten lesbaren Lösungen ist wahrscheinlich der beste Ansatz, wenn Sie sich nicht in einem leistungskritischen Codepfad befinden. Um zu sehen, wie sich die Lösungen stapeln, finden Sie hier einen Leistungsvergleich aller bisher vorgeschlagenen Methoden. check_trans verwendet die Methode string.translate.
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):returnnot 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.returnnot pat_inv.search(s)def check_trans(s):returnnot 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))printif __name__=='__main__': main()
Der Übersetzungsansatz scheint in den meisten Fällen am besten zu sein, dramatisch mit langen gültigen Zeichenfolgen, wird jedoch von Regexen in test_long_invalid übertroffen (vermutlich, weil die Regex sofort aussteigen kann, aber die Übersetzung muss immer die gesamte Zeichenfolge scannen). Die festgelegten Ansätze sind normalerweise am schlechtesten und schlagen reguläre Ausdrücke nur für den Fall eines leeren Strings.
Die Verwendung von all (x in allow_set für x in s) funktioniert gut, wenn es vorzeitig beendet wird, kann jedoch schlecht sein, wenn jedes Zeichen durchlaufen werden muss. isSubSet und Set-Differenz sind vergleichbar und unabhängig von den Daten konsistent proportional zur Länge der Zeichenfolge.
Es gibt einen ähnlichen Unterschied zwischen den Regex-Methoden, die allen gültigen Zeichen entsprechen, und der Suche nach ungültigen Zeichen. Die Übereinstimmung ist etwas besser, wenn nach einer langen, aber vollständig gültigen Zeichenfolge gesucht wird, bei ungültigen Zeichen am Ende der Zeichenfolge jedoch schlechter.
Verwenden Sie string.ascii_lettersanstelle von, string.letterswenn Sie das Flag re.LOCALE nicht für reguläre Ausdrücke verwenden (andernfalls erhalten Sie möglicherweise falsch positive Ergebnisse in check_trans(). Funktioniert string.maketrans()nicht für Unicode-Zeichenfolgen.
jfs
from __future__ import unicode_literalsVerwenden Sie für Python 3 / Unicode / ) trans_table3 = dict((ord(char), '') for char in allowed_chars)und def check_trans(s): return not s.translate(trans_table3). Im Allgemeinen ist die Leistung jedoch schlechter als bei den RE-Versionen.
Hugo
14
Es gibt verschiedene Möglichkeiten, dieses Ziel zu erreichen. Einige sind klarer als andere. Für jedes meiner Beispiele bedeutet "True", dass die übergebene Zeichenfolge gültig ist. "False" bedeutet, dass sie ungültige Zeichen enthält.
Zuallererst 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 wird ein regulärer Ausdruck verwendet. Sie können dies mit re.match () tun. Beachten Sie, dass '-' am Ende von [] stehen muss, sonst wird es als 'Bereichs'-Begrenzer verwendet. Beachten Sie auch das $, was "Ende der Zeichenfolge" bedeutet. Andere Antworten in dieser Frage verwenden eine Sonderzeichenklasse, '\ w'. Ich bevorzuge immer die Verwendung eines expliziten Zeichenklassenbereichs mit [], da es einfacher zu verstehen ist, ohne eine Kurzanleitung nachschlagen zu müssen, und einfacher zu verwenden ist. 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 Sie eine inverse Übereinstimmung mit regulären Ausdrücken durchführen können. Das habe ich jetzt hier aufgenommen. Beachten Sie, dass [^ ...] die Zeichenklasse invertiert, da ^ verwendet wird:
Sie können mit dem 'set'-Objekt auch etwas Kniffliges tun. Schauen Sie sich dieses Beispiel an, in dem alle zulässigen Zeichen aus der ursprünglichen Zeichenfolge entfernt werden und wir einen Satz erhalten, der entweder a) nichts oder b) die beleidigenden Zeichen aus der Zeichenfolge enthält:
In Ihrem ersten Regex-Test sollte "[a-zA-Z0-9 _-] + $" nicht "[a-zA-Z0-9 _-] * $" sein. Die leere Zeichenfolge sollte wahrscheinlich als übereinstimmend betrachtet werden.
Brian
Verwenden string.ascii_lettersSie diese Option, wenn Sie reguläre Ausdrücke '[a-zA-Z]' verwenden.
JFS
12
Ohne die Striche und Unterstriche wäre die einfachste Lösung
Alternativ zur Verwendung von Regex können Sie dies in Sets tun:
from sets importSet
allowed_chars =Set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-')ifSet(my_little_sting).issubset(allowed_chars):# your actionprintTrue
import re;
re.fullmatch("^[\w-]+$", target_string)# fullmatch looks also workable for python 3.4
\w: Nur [a-zA-Z0-9_]
Sie müssen also -char hinzufügen, um den Bindestrich char zu rechtfertigen.
+: Entspricht einer oder mehreren Wiederholungen des vorhergehenden Zeichens. Ich denke, Sie akzeptieren keine leeren Eingaben. Aber wenn Sie dies tun, wechseln Sie zu *.
^: Entspricht dem Anfang der Zeichenfolge.
$: Entspricht dem Ende der Zeichenfolge.
Sie benötigen diese beiden Sonderzeichen, da Sie den folgenden Fall vermeiden müssen. Die unerwünschten Zeichen wie &hier werden möglicherweise zwischen den übereinstimmenden Mustern angezeigt.
Nun, du kannst Regex um Hilfe bitten, die hier großartig ist :)
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'
Sie könnten immer ein Listenverständnis verwenden und die Ergebnisse mit allen überprüfen. Dies wäre etwas weniger ressourcenintensiv als die Verwendung eines regulären Ausdrucks: all([c in string.letters + string.digits + ["_", "-"] for c in mystring])
Bitte testen Sie Ihren Code vor dem Posten. Eine Lösung basierend auf Ihrer fehlerhaften Antwort, die ausgeführt wird, lautet: all (c in string.letters + string.digits + "_" für c in mystring)
Jerub
2
Das ist viel los zu sein , mehr Ressourcen als ein regex. Es wird ein linearer Scan für jedes Zeichen durchgeführt (besser, um einen Satz im Voraus zu erstellen), und Sie erstellen unnötig eine Liste, wenn ein Generatorverständnis leichter wäre.
Brian
-1
Hier ist etwas, das auf Jerubs "naivem Ansatz" basiert (naiv sind seine Worte, nicht meine!):
import string
ALLOWED = frozenset(string.ascii_letters + string.digits +'_'+'-')def check(mystring):return all(c in ALLOWED for c in mystring)
Wenn ALLOWEDes sich um eine Zeichenfolge handelt c in ALLOWED, muss meines Erachtens jedes Zeichen in der Zeichenfolge durchlaufen werden, bis eine Übereinstimmung gefunden oder das Ende erreicht wurde. Was, um Joel Spolsky zu zitieren, so etwas wie ein Shlemiel the Painter-Algorithmus ist .
Das Testen der Existenz in einem Satz sollte jedoch effizienter sein oder zumindest weniger von der Anzahl der zulässigen Zeichen abhängen. Sicher ist dieser Ansatz auf meiner Maschine etwas schneller. Es ist klar und ich denke, es funktioniert in den meisten Fällen gut genug (auf meiner langsamen Maschine kann ich Zehntausende von kurzen Strings in Sekundenbruchteilen validieren). Ich mag das.
Tatsächlich funktioniert ein regulärer Ausdruck auf meinem Computer um ein Vielfaches schneller und ist genauso einfach (wohl einfacher). Das ist wahrscheinlich der beste Weg nach vorne.
Alle diese Zeichen müssen in einer Klasse sein, sonst erhalten Sie falsche Negative. Außerdem haben Sie vergessen, die Markierungen für den Anfang der Zeichenfolge und das Ende der Zeichenfolge einzuschließen. Auf diese Weise stimmt sie immer überein, solange ein gültiges Zeichen vorhanden ist.
Thomas
1
Dies stimmt auch dann überein, wenn keine gültigen Zeichen vorhanden sind. Nulllängenübereinstimmung. Es ist auch nicht in Python.
Antworten:
Ein regulärer Ausdruck reicht mit sehr wenig Code aus:
quelle
\w
beinhaltet\d
und_
daherisvalid = re.match(r'[\w-]+$', astr)
oderisinvalid = re.search(r'[^\w-]', astr)
. Ein mögliches Vorhandensein vonlocale.setlocale
oder Unicode-Zeichenfolgen erfordert zusätzliche Überlegungen.isvalid = re.match(r'[\w-]*$', astr)
- Leere Zeichenfolgen sind gültig.[Bearbeiten] Es gibt eine andere Lösung, die noch nicht erwähnt wurde, und sie scheint in den meisten Fällen die anderen bisherigen zu übertreffen.
Verwenden Sie string.translate, um alle gültigen Zeichen in der Zeichenfolge zu ersetzen, und prüfen Sie, ob noch ungültige Zeichen übrig sind. Dies ist ziemlich schnell, da die zugrunde liegende C-Funktion für die Arbeit verwendet wird und nur sehr wenig Python-Bytecode erforderlich ist.
Offensichtlich ist Leistung nicht alles - die Suche nach den am besten lesbaren Lösungen ist wahrscheinlich der beste Ansatz, wenn Sie sich nicht in einem leistungskritischen Codepfad befinden. Um zu sehen, wie sich die Lösungen stapeln, finden Sie hier einen Leistungsvergleich aller bisher vorgeschlagenen Methoden. check_trans verwendet die Methode string.translate.
Testcode:
Die Ergebnisse auf meinem System sind:
Der Übersetzungsansatz scheint in den meisten Fällen am besten zu sein, dramatisch mit langen gültigen Zeichenfolgen, wird jedoch von Regexen in test_long_invalid übertroffen (vermutlich, weil die Regex sofort aussteigen kann, aber die Übersetzung muss immer die gesamte Zeichenfolge scannen). Die festgelegten Ansätze sind normalerweise am schlechtesten und schlagen reguläre Ausdrücke nur für den Fall eines leeren Strings.
Die Verwendung von all (x in allow_set für x in s) funktioniert gut, wenn es vorzeitig beendet wird, kann jedoch schlecht sein, wenn jedes Zeichen durchlaufen werden muss. isSubSet und Set-Differenz sind vergleichbar und unabhängig von den Daten konsistent proportional zur Länge der Zeichenfolge.
Es gibt einen ähnlichen Unterschied zwischen den Regex-Methoden, die allen gültigen Zeichen entsprechen, und der Suche nach ungültigen Zeichen. Die Übereinstimmung ist etwas besser, wenn nach einer langen, aber vollständig gültigen Zeichenfolge gesucht wird, bei ungültigen Zeichen am Ende der Zeichenfolge jedoch schlechter.
quelle
string.ascii_letters
anstelle von,string.letters
wenn Sie das Flag re.LOCALE nicht für reguläre Ausdrücke verwenden (andernfalls erhalten Sie möglicherweise falsch positive Ergebnisse incheck_trans()
. Funktioniertstring.maketrans()
nicht für Unicode-Zeichenfolgen.from __future__ import unicode_literals
Verwenden Sie für Python 3 / Unicode / )trans_table3 = dict((ord(char), '') for char in allowed_chars)
und defcheck_trans(s): return not s.translate(trans_table3)
. Im Allgemeinen ist die Leistung jedoch schlechter als bei den RE-Versionen.Es gibt verschiedene Möglichkeiten, dieses Ziel zu erreichen. Einige sind klarer als andere. Für jedes meiner Beispiele bedeutet "True", dass die übergebene Zeichenfolge gültig ist. "False" bedeutet, dass sie ungültige Zeichen enthält.
Zuallererst gibt es den naiven Ansatz:
Dann wird ein regulärer Ausdruck verwendet. Sie können dies mit re.match () tun. Beachten Sie, dass '-' am Ende von [] stehen muss, sonst wird es als 'Bereichs'-Begrenzer verwendet. Beachten Sie auch das $, was "Ende der Zeichenfolge" bedeutet. Andere Antworten in dieser Frage verwenden eine Sonderzeichenklasse, '\ w'. Ich bevorzuge immer die Verwendung eines expliziten Zeichenklassenbereichs mit [], da es einfacher zu verstehen ist, ohne eine Kurzanleitung nachschlagen zu müssen, und einfacher zu verwenden ist. Fall.
Eine andere Lösung stellte fest, dass Sie eine inverse Übereinstimmung mit regulären Ausdrücken durchführen können. Das habe ich jetzt hier aufgenommen. Beachten Sie, dass [^ ...] die Zeichenklasse invertiert, da ^ verwendet wird:
Sie können mit dem 'set'-Objekt auch etwas Kniffliges tun. Schauen Sie sich dieses Beispiel an, in dem alle zulässigen Zeichen aus der ursprünglichen Zeichenfolge entfernt werden und wir einen Satz erhalten, der entweder a) nichts oder b) die beleidigenden Zeichen aus der Zeichenfolge enthält:
quelle
string.ascii_letters
Sie diese Option, wenn Sie reguläre Ausdrücke '[a-zA-Z]' verwenden.Ohne die Striche und Unterstriche wäre die einfachste Lösung
(Abschnitt 3.6.1 der Python-Bibliotheksreferenz)
quelle
Alternativ zur Verwendung von Regex können Sie dies in Sets tun:
quelle
quelle
Regulärer Ausdruck kann sehr flexibel sein.
\w
: Nur[a-zA-Z0-9_]
Sie müssen also
-
char hinzufügen, um den Bindestrich char zu rechtfertigen.+
: Entspricht einer oder mehreren Wiederholungen des vorhergehenden Zeichens. Ich denke, Sie akzeptieren keine leeren Eingaben. Aber wenn Sie dies tun, wechseln Sie zu*
.^
: Entspricht dem Anfang der Zeichenfolge.$
: Entspricht dem Ende der Zeichenfolge.Sie benötigen diese beiden Sonderzeichen, da Sie den folgenden Fall vermeiden müssen. Die unerwünschten Zeichen wie
&
hier werden möglicherweise zwischen den übereinstimmenden Mustern angezeigt.&&&PATTERN&&PATTERN
quelle
Nun, du kannst Regex um Hilfe bitten, die hier großartig ist :)
Code:
Ausgabe:
Hoffe das hilft :)
quelle
Sie könnten immer ein Listenverständnis verwenden und die Ergebnisse mit allen überprüfen. Dies wäre etwas weniger ressourcenintensiv als die Verwendung eines regulären Ausdrucks:
all([c in string.letters + string.digits + ["_", "-"] for c in mystring])
quelle
Hier ist etwas, das auf Jerubs "naivem Ansatz" basiert (naiv sind seine Worte, nicht meine!):
Wenn
ALLOWED
es sich um eine Zeichenfolge handeltc in ALLOWED
, muss meines Erachtens jedes Zeichen in der Zeichenfolge durchlaufen werden, bis eine Übereinstimmung gefunden oder das Ende erreicht wurde. Was, um Joel Spolsky zu zitieren, so etwas wie ein Shlemiel the Painter-Algorithmus ist .Das Testen der Existenz in einem Satz sollte jedoch effizienter sein oder zumindest weniger von der Anzahl der zulässigen Zeichen abhängen. Sicher ist dieser Ansatz auf meiner Maschine etwas schneller. Es ist klar und ich denke, es funktioniert in den meisten Fällen gut genug (auf meiner langsamen Maschine kann ich Zehntausende von kurzen Strings in Sekundenbruchteilen validieren). Ich mag das.
Tatsächlich funktioniert ein regulärer Ausdruck auf meinem Computer um ein Vielfaches schneller und ist genauso einfach (wohl einfacher). Das ist wahrscheinlich der beste Weg nach vorne.
quelle
Verwenden Sie einen regulären Ausdruck und prüfen Sie, ob er übereinstimmt!
quelle