Dizedeki tüm karakterleri yinelersem bunun nasıl yapıldığını biliyorum ama daha şık bir yöntem arıyorum.
Düzenli bir ifade çok az kod ile hile yapacak:
import re
...
if re.match("^[A-Za-z0-9_-]*$", my_little_string):
# do something here
[Düzenle] Henüz belirtilmeyen başka bir çözüm var ve çoğu durumda şu ana kadar verilmiş olanlardan daha iyi görünüyor.
Dize içindeki tüm geçerli karakterleri değiştirmek için string.translate komutunu kullanın ve geride geçersiz karakterler olup olmadığına bakın. Çok az python bytecode ile çalışmak için, temel C işlevini kullandığından, bu oldukça hızlı.
Açıkçası, performans her şey değildir - en okunaklı çözümlere gitmek, performans açısından kritik bir kodepatta olmasa da en iyi yaklaşımdır, ancak yalnızca çözümlerin nasıl biriktiğini görmek için, işte şimdiye kadar önerilen tüm yöntemlerin performans karşılaştırması. check_trans string.translate metodunu kullanandır.
Test kodu:
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()
Sistemimdeki sonuçlar:
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
Tercümanlık yaklaşımı çoğu durumda en iyi şekilde görünür, dramatik şekilde uzun geçerli dizelerle, ancak test_long_invalid içindeki regex'ler tarafından dövülür (Muhtemelen regex'in hemen kaybedebileceği, ancak çeviri her zaman tüm dizeyi taraması gerektiği için). Ayarlanan yaklaşımlar genellikle en kötü olanıdır, yalnızca boş string case için regex'ler atar.
All (x in s için x in allow_set) komutunun kullanılması, erken ayrılırsa iyi performans gösterir, ancak her karakterde yinelenmek zorunda kalırsa kötü olabilir. isSubSet ve ayarlanan fark karşılaştırılabilir ve verilere bakılmaksızın dizenin uzunluğu ile tutarlı bir şekilde orantılıdır.
Tüm geçerli karakterlerle eşleşen ve geçersiz karakterler ararken regex yöntemleri arasında benzer bir fark var. Eşleştirme, uzun, ancak tam olarak geçerli bir dize denetlerken biraz daha iyi performans gösterir, ancak dize sonuna yakın geçersiz karakterler için daha kötüdür.
Bu hedefe ulaşmak için çeşitli yollar vardır, bazıları diğerlerinden daha açıktır. Örneklerimin her biri için 'Doğru', geçirilen dizenin geçerli olduğu, 'Yanlış' ise geçersiz karakterler içerdiği anlamına gelir.
Her şeyden önce, saf bir yaklaşım var:
import string
allowed = string.letters + string.digits + '_' + '-'
def check_naive(mystring):
return all(c in allowed for c in mystring)
Sonra normal bir ifadenin kullanımı var, bunu re.match () ile yapabilirsiniz. '-' nin [] sonunda olması gerektiğini unutmayın, aksi takdirde 'aralık' sınırlayıcısı olarak kullanılır. Ayrıca 'dizgenin sonu' anlamına gelen $ 'a da dikkat edin. Bu soruya not edilen diğer cevaplar özel bir karakter sınıfı kullanır: '\ w'. vaka.
import re
CHECK_RE = re.compile('[a-zA-Z0-9_-]+$')
def check_re(mystring):
return CHECK_RE.match(mystring)
Başka bir çözüm, düzenli ifadelerle ters bir eşleşme yapabileceğinizi belirtti, bunu şimdi buraya dahil ettim. ^ Kullanıldığından, [^ ...] karakter sınıfını tersine çevirir:
CHECK_INV_RE = re.compile('[^a-zA-Z0-9_-]')
def check_inv_re(mystring):
return not CHECK_INV_RE.search(mystring)
Ayrıca 'set' nesnesiyle zor bir şey de yapabilirsiniz. Orijinal diziden izin verilen tüm karakterleri kaldıran, bizi a) hiçbir şey ya da b) dizeden rahatsız edici karakterleri içeren bir kümeyle bırakan bu örneğe bir göz atın:
def check_set(mystring):
return not set(mystring) - set(allowed)
Çizgiler ve alt çizgiler için olmasaydı, en kolay çözüm
my_little_string.isalnum()
(Bölüm 3.6.1 Python Kütüphanesi Referansı)
Regex kullanmaya alternatif olarak bunu Setler'de yapabilirsiniz:
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)
Regex'in yardımını isteyebilirsin, buradaki harika :)
kod:
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'
Çıktı:
yes
Bu yardımcı olur umarım :)
Her zaman bir liste anlayışı kullanabilir ve sonuçları tümüyle kontrol edebilirsiniz, bir regex kullanmaktan daha az kaynak yoğun olurdu: all([c in string.letters + string.digits + ["_", "-"] for c in mystring])
Düzenli ifade çok esnek olabilir.
import re;
re.fullmatch("^[\w-]+$", target_string) # fullmatch starts from python 3.4 `match` looks also workable here
\w
: Sadece [a-zA-Z0-9_]
Yani -
char eklemeniz gerekir.
+
: Önceki karakterin bir veya daha fazla tekrarını eşleştirin. Sanırım boş girdi kabul etmiyorsun. Ancak yaparsanız, *
olarak değiştirin.
^
: Dizenin başlangıcını eşleştirir.
$
: Dizenin sonuyla eşleşir.
Aşağıdaki iki durumdan kaçınmanız gerektiğinden bu iki özel karaktere ihtiyacınız var:
&&&PATTERN&&PATTERN
İstemediğiniz kalıp, muhtemelen istediğiniz kalıpların arasında oturabilir.
Bu örnek için: &&&
beklediğiniz durumda değil ama legal
dizesi kabul edilebilir. Normal ifadeye ^
ve $
eklemezseniz, bu düzen yanlış düzenle eşleşir.
İşte Jerub'un "naif yaklaşımını" temel alan bir şey (saf onun sözleri, benim değil!):
import string
ALLOWED = frozenset(string.ascii_letters + string.digits + '_' + '-')
def check(mystring):
return all(c in ALLOWED for c in mystring)
ALLOWED
bir dize olsaydı, bence c in ALLOWED
, bir eşleşme bulana veya sonuna ulaşana kadar dizedeki her karakterin üzerinde yineleme yapmayı içerir. Joel Spolsky'den alıntı yapmak gerekirse, Ressam algoritmasını Shlemiel olan bir şey.
Ancak, bir küme içinde varlık testi, daha verimli olmalı veya en azından izin verilen karakter sayısına bağlı olmalıdır. Elbette bu yaklaşım makinemde biraz daha hızlı. Açıktır ve çoğu durumda yeterince iyi performans gösterdiğini düşünüyorum (yavaş makinemde on saniyelik kısa isikli ipleri bir saniyenin bir bölümünde doğrulayabilirim). Bunu sevdim.
ASLINDA makinemde bir regexp birkaç kat daha hızlı çalışıyor ve bu kadar basittir (tartışmasız daha basit). Yani bu muhtemelen en iyi yoldur.