Saya tahu bagaimana melakukan ini jika saya mengulangi semua karakter dalam string tetapi saya mencari metode yang lebih elegan.
Ekspresi reguler akan melakukan trik dengan kode yang sangat sedikit:
import re
...
if re.match("^[A-Za-z0-9_-]*$", my_little_string):
# do something here
[Sunting] Ada solusi lain yang belum disebutkan, dan tampaknya mengungguli yang lain yang diberikan sejauh ini dalam kebanyakan kasus.
Gunakan string.translate untuk mengganti semua karakter yang valid dalam string, dan lihat apakah kita memiliki yang tidak valid yang tersisa. Ini cukup cepat karena menggunakan fungsi C yang mendasarinya untuk melakukan pekerjaan, dengan bytecode python sangat sedikit yang terlibat.
Jelas kinerja bukanlah segalanya - mencari solusi yang paling mudah dibaca mungkin adalah pendekatan terbaik ketika tidak berada dalam codepath kritis kinerja, tetapi hanya untuk melihat bagaimana solusi menumpuk, inilah perbandingan kinerja semua metode yang diusulkan sejauh ini. check_trans adalah yang menggunakan metode string.translate.
Kode uji:
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()
Hasil pada sistem saya adalah:
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
Pendekatan penerjemahan tampaknya paling baik dalam banyak kasus, secara dramatis demikian dengan string yang panjang dan valid, tetapi dikalahkan oleh regex di test_long_invalid (Mungkin karena regex dapat segera menebus, tetapi menerjemahkan selalu harus memindai seluruh string). Pendekatan himpunan biasanya terburuk, mengalahkan regex hanya untuk kasus string kosong.
Menggunakan semua (x di allow_set untuk x dalam s) berkinerja baik jika menebus lebih awal, tetapi bisa buruk jika harus mengulangi setiap karakter. isSubSet dan perbedaan set sebanding, dan secara konsisten sebanding dengan panjang string terlepas dari data.
Ada perbedaan yang serupa antara metode regex yang cocok dengan semua karakter yang valid dan mencari karakter yang tidak valid. Pencocokan berkinerja lebih baik ketika memeriksa string yang panjang, tetapi sepenuhnya valid, tetapi lebih buruk untuk karakter yang tidak valid di dekat akhir string.
Ada berbagai cara untuk mencapai tujuan ini, ada yang lebih jelas daripada yang lain. Untuk masing-masing contoh saya, 'Benar' berarti bahwa string yang dikirimkan adalah benar, 'Salah' artinya berisi karakter yang tidak valid.
Pertama-tama, ada pendekatan naif:
import string
allowed = string.letters + string.digits + '_' + '-'
def check_naive(mystring):
return all(c in allowed for c in mystring)
Lalu ada penggunaan ekspresi reguler, Anda bisa melakukan ini dengan re.match (). Perhatikan bahwa '-' harus di akhir [] jika tidak maka akan digunakan sebagai pembatas 'rentang'. Perhatikan juga $ yang berarti 'akhir dari string'. Jawaban lain yang dicatat dalam pertanyaan ini menggunakan kelas karakter khusus, '\ w', saya selalu lebih suka menggunakan rentang kelas karakter eksplisit menggunakan [] karena lebih mudah dipahami tanpa harus mencari panduan referensi cepat, dan lebih mudah untuk kasus.
import re
CHECK_RE = re.compile('[a-zA-Z0-9_-]+$')
def check_re(mystring):
return CHECK_RE.match(mystring)
Solusi lain mencatat bahwa Anda dapat melakukan kecocokan terbalik dengan ekspresi reguler, saya sudah memasukkannya di sini sekarang. Perhatikan bahwa [^ ...] membalikkan kelas karakter karena ^ digunakan:
CHECK_INV_RE = re.compile('[^a-zA-Z0-9_-]')
def check_inv_re(mystring):
return not CHECK_INV_RE.search(mystring)
Anda juga dapat melakukan sesuatu yang rumit dengan objek 'set'. Lihat contoh ini, yang menghapus dari string asli semua karakter yang diizinkan, meninggalkan kita dengan set yang mengandung a) tidak ada, atau b) karakter yang menyinggung dari string:
def check_set(mystring):
return not set(mystring) - set(allowed)
Jika bukan karena garis putus-putus dan garis bawah, solusi termudah adalah
my_little_string.isalnum()
(Bagian 3.6.1 dari Referensi Python Library)
Sebagai alternatif untuk menggunakan regex Anda bisa melakukannya di 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)
Nah Anda bisa meminta bantuan regex, hebat di sini :)
kode:
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'
Keluaran:
yes
Semoga ini membantu :)
Anda selalu bisa menggunakan daftar pemahaman dan memeriksa hasilnya dengan semua, itu akan menjadi sumber daya sedikit kurang intensif daripada menggunakan regex: all([c in string.letters + string.digits + ["_", "-"] for c in mystring])
Ekspresi reguler bisa sangat fleksibel.
import re;
re.fullmatch("^[\w-]+$", target_string) # fullmatch starts from python 3.4 `match` looks also workable here
\w
: Hanya [a-zA-Z0-9_]
Jadi, Anda perlu menambahkan char -
.
+
: Cocokkan satu atau lebih pengulangan char sebelumnya. Saya kira Anda tidak menerima input kosong. Tetapi jika Anda melakukannya, ubah ke *
.
^
: Cocok dengan awal string.
$
: Cocok dengan akhir string.
Anda memerlukan dua karakter khusus ini karena Anda harus menghindari kasus berikut:
&&&PATTERN&&PATTERN
Pola yang tidak Anda inginkan mungkin duduk di antara pola yang Anda inginkan.
Untuk contoh ini: &&&
bukan kasus yang Anda harapkan tetapi string legal
dapat diterima. Jika Anda tidak menambahkan ^
dan $
ke ekspresi reguler, maka pola ini akan cocok dengan pola yang salah.
Berikut ini sesuatu yang didasarkan pada "pendekatan naif" Jerub (naif menjadi kata-katanya, bukan milikku!):
import string
ALLOWED = frozenset(string.ascii_letters + string.digits + '_' + '-')
def check(mystring):
return all(c in ALLOWED for c in mystring)
Jika ALLOWED
adalah string maka saya pikir c in ALLOWED
akan melibatkan iterasi setiap karakter dalam string hingga ditemukan kecocokan atau mencapai akhir. Yang, mengutip Joel Spolsky, adalah sesuatu dari Shlemiel algoritma Painter .
Tetapi pengujian keberadaan dalam satu set harus lebih efisien, atau setidaknya kurang tergantung pada jumlah karakter yang diperbolehkan. Tentu saja pendekatan ini sedikit lebih cepat di komputer saya. Sudah jelas dan saya pikir kinerjanya cukup baik untuk kebanyakan kasus (pada mesin lambat saya, saya dapat memvalidasi puluhan ribu string pendek dalam sepersekian detik). Saya suka itu.
SEBENARNYA pada komputer saya regexp bekerja beberapa kali lebih cepat, dan sesederhana ini (bisa dibilang lebih sederhana). Jadi itu mungkin cara terbaik ke depan.