मैं कैसे सत्यापित करूं कि एक स्ट्रिंग में केवल अक्षर, संख्या, अंडरस्कोर और डैश शामिल हैं?


86

मुझे पता है कि यह कैसे करना है अगर मैं स्ट्रिंग के सभी पात्रों के माध्यम से पुनरावृति करता हूं, लेकिन मैं अधिक सुरुचिपूर्ण विधि की तलाश कर रहा हूं।


5
क्या आप असिसी, स्थानीय-विशिष्ट या यूनिकोड अक्षरों के बारे में बात कर रहे हैं?
jfs

जवाबों:


122

एक नियमित अभिव्यक्ति बहुत कम कोड के साथ चाल करेगी:

import re

...

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

25
आप इसे सरल कर सकते हैं: ^ [\ w \ d _-] * $
Prestaul

13
यह समाधान उन तारों से मेल खाएगा जो शून्य लंबाई के हैं। का उपयोग करें + के बजाय * यह 1 या अधिक वर्णों के तार से मेल खाने के लिए।
जेरुब

10
@Prestaul: \wशामिल हैं \dऔर _इसलिए isvalid = re.match(r'[\w-]+$', astr)या isinvalid = re.search(r'[^\w-]', astr)locale.setlocaleया यूनिकोड स्ट्रिंग्स की एक संभावित उपस्थिति के लिए अतिरिक्त विचार की आवश्यकता होती है।
jfs

1
सुधार: isvalid = re.match(r'[\w-]*$', astr)- खाली तार मान्य हैं।
jfs

आप उस रेगेक्स में एक अवधि / डॉट (।) की अनुमति कैसे दे सकते हैं? संपादित करें, यहां बताया गया है: ^ [a-zA-Z0-9
-__

24

[संपादित करें] अभी तक उल्लेखित एक और समाधान नहीं है, और यह अधिकांश मामलों में अब तक दिए गए अन्य लोगों से बेहतर प्रदर्शन करता है।

स्ट्रिंग में सभी मान्य वर्णों को बदलने के लिए string.translate का उपयोग करें, और देखें कि क्या हमारे पास कोई अमान्य अक्षर बचा है। यह बहुत तेज है क्योंकि यह काम करने के लिए अंतर्निहित सी फ़ंक्शन का उपयोग करता है, जिसमें बहुत कम अजगर बाइटकोड शामिल हैं।

स्पष्ट रूप से प्रदर्शन सब कुछ नहीं है - सबसे पठनीय समाधानों के लिए जाना संभवतः सबसे अच्छा तरीका है जब एक प्रदर्शन महत्वपूर्ण कोडपैथ में नहीं है, लेकिन यह देखने के लिए कि समाधान कैसे ढेर हो जाता है, यहां अब तक प्रस्तावित सभी तरीकों की प्रदर्शन तुलना है। check_trans string.translate पद्धति का उपयोग करने वाला है।

टेस्ट कोड:

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()

मेरे सिस्टम पर परिणाम हैं:

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

अनुवाद का दृष्टिकोण ज्यादातर मामलों में सबसे अच्छा लगता है, इसलिए नाटकीय रूप से लंबे वैध तार के साथ, लेकिन test_long_invalid में regexes द्वारा पीटा जाता है (संभवतः क्योंकि regex तुरंत बाहर निकल सकता है, लेकिन अनुवाद को हमेशा पूरे स्ट्रिंग को स्कैन करना पड़ता है)। सेट अप दृष्टिकोण आमतौर पर सबसे खराब होते हैं, केवल खाली स्ट्रिंग मामले के लिए रेगीक्स को पीटना।

सभी का उपयोग करना (एक्स फॉर एस में एक्स के लिए allow_set) अच्छा प्रदर्शन करता है अगर यह जल्दी से बाहर निकलता है, लेकिन बुरा हो सकता है अगर इसे हर चरित्र के माध्यम से पुनरावृत्त करना है। isSubSet और सेट अंतर तुलनीय हैं, और डेटा की परवाह किए बिना स्ट्रिंग की लंबाई के लिए लगातार आनुपातिक हैं।

सभी मान्य वर्णों के मिलान और अमान्य वर्णों की खोज करने के लिए रेगेक्स विधियों के बीच समान अंतर है। लंबे समय तक जांच करने पर मिलान करना थोड़ा बेहतर होता है, लेकिन पूरी तरह से वैध स्ट्रिंग, लेकिन स्ट्रिंग के अंत के पास अमान्य वर्णों के लिए बदतर।


1
यदि आप regexps के लिए re.LOCALE ध्वज का उपयोग नहीं करते हैं string.ascii_letters, string.lettersतो इसके बजाय का उपयोग करें (अन्यथा आप में झूठे सकारात्मक परिणाम प्राप्त कर सकते हैं check_trans()string.maketrans()यूनिकोड स्ट्रिंग्स के लिए काम नहीं करेंगे।
jfs jfs)

पायथन 3 / यूनिकोड / from __future__ import unicode_literals) के लिए, उपयोग trans_table3 = dict((ord(char), '') for char in allowed_chars)और डीफ़ check_trans(s): return not s.translate(trans_table3)। लेकिन सामान्य तौर पर, यह आरई संस्करणों से भी बदतर प्रदर्शन करता है।
ह्यूगो

14

इस लक्ष्य को प्राप्त करने के कई तरीके हैं, कुछ दूसरों की तुलना में स्पष्ट हैं। मेरे प्रत्येक उदाहरण के लिए, 'ट्रू' का अर्थ है कि पारित स्ट्रिंग मान्य है, 'गलत' का अर्थ है कि इसमें अमान्य वर्ण हैं।

सबसे पहले, वहाँ भोली दृष्टिकोण है:

import string
allowed = string.letters + string.digits + '_' + '-'

def check_naive(mystring):
    return all(c in allowed for c in mystring)

फिर एक नियमित अभिव्यक्ति का उपयोग होता है, आप इसे re.match () के साथ कर सकते हैं। ध्यान दें कि '-' के अंत में होना चाहिए] अन्यथा इसका उपयोग 'रेंज' सीमांकक के रूप में किया जाएगा। उस $ को भी नोट करें जिसका अर्थ है 'स्ट्रिंग का अंत'। इस प्रश्न में दिए गए अन्य उत्तर एक विशेष चरित्र वर्ग, '\ w' का उपयोग करते हैं, मैं हमेशा [] का उपयोग करते हुए एक स्पष्ट वर्ण वर्ग श्रेणी का उपयोग करना पसंद करता हूं, क्योंकि एक त्वरित संदर्भ गाइड को देखने के बिना समझना आसान है, और विशेष के लिए आसान है- मामला।

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

एक अन्य समाधान ने नोट किया कि आप नियमित अभिव्यक्ति के साथ एक उलटा मैच कर सकते हैं, मैंने इसे अब यहां शामिल किया है। ध्यान दें कि [^ ...] वर्ण वर्ग को प्रभावित करता है क्योंकि ^ का उपयोग किया जाता है:

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

आप 'सेट' ऑब्जेक्ट के साथ कुछ मुश्किल भी कर सकते हैं। इस उदाहरण पर एक नज़र डालें, जो मूल स्ट्रिंग से हटाए जाने वाले सभी वर्णों को हटा देता है, हमें एक सेट के साथ छोड़कर) क कुछ भी नहीं है, या ख) स्ट्रिंग से अपमानजनक वर्ण:

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

आपके पहले रेगेक्स टेस्ट में, "[a-zA-Z0-9 _-] + $" नहीं होना चाहिए [[a-zA-Z0-9 _-] * $ "। खाली स्ट्रिंग को शायद मिलान के रूप में माना जाना चाहिए।
ब्रायन

का प्रयोग करें string.ascii_lettersअगर आप '[a-zA-Z]' regexps का उपयोग करें।
jfs

12

यदि यह डैश और अंडरस्कोर के लिए नहीं था, तो सबसे आसान समाधान होगा

my_little_string.isalnum()

( पायथन लाइब्रेरी संदर्भ की धारा 3.6.1 )


दुर्भाग्य से लिंक कोई और काम नहीं कर रहा है, लेकिन यहां प्रासंगिक अनुभाग पायथन »3.3.6 प्रलेखन» पायथन स्टैंडर्ड लाइब्रेरी »4.7.1 है। स्ट्रिंग के तरीके । धन्यवाद @Ber यह वही है जो मुझे चाहिए था।
थानोस

4

रेगेक्स का उपयोग करने के विकल्प के रूप में आप इसे सेट्स में कर सकते हैं:

from sets import Set

allowed_chars = Set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-')

if Set(my_little_sting).issubset(allowed_chars):
    # your action
    print True


1

नियमित अभिव्यक्ति बहुत लचीली हो सकती है।

import re;
re.fullmatch("^[\w-]+$", target_string) # fullmatch looks also workable for python 3.4

\w: केवल [a-zA-Z0-9_]

इसलिए आपको -हाइफ़न चार को सही ठहराने के लिए चार जोड़ना होगा ।

+: पूर्ववर्ती चार्ट के एक या अधिक दोहराव का मिलान करें। मुझे लगता है कि आप रिक्त इनपुट को स्वीकार नहीं करते हैं। लेकिन अगर आप ऐसा करते हैं, तो बदलिए *

^: स्ट्रिंग की शुरुआत से मेल खाता है।

$: स्ट्रिंग के अंत से मेल खाता है।

आपको इन दो विशेष पात्रों की आवश्यकता है क्योंकि आपको निम्नलिखित मामले से बचने की आवश्यकता है। यहाँ के अनचाहे वर्ण &मिलान पैटर्न के बीच दिखाई दे सकते हैं।

&&&PATTERN&&PATTERN


0

वैसे आप रेगेक्स की मदद पूछ सकते हैं, यहाँ महान :)

कोड:

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'

आउटपुट:

yes  

उम्मीद है की यह मदद करेगा :)


-1

आप हमेशा एक सूची समझ का उपयोग कर सकते हैं और सभी के साथ परिणामों की जांच कर सकते हैं, यह रेगेक्स का उपयोग करने की तुलना में थोड़ा कम संसाधन गहन होगा: all([c in string.letters + string.digits + ["_", "-"] for c in mystring])


कृपया पोस्ट करने से पहले अपने कोड का परीक्षण करें। आपके टूटे हुए उत्तर के आधार पर एक समाधान जो चलता है: सभी (c in string.letters + string.digits + "_" in cring के लिए)
जेरब

2
रेक्स की तुलना में यह अधिक संसाधन गहन होने वाला है। यह हर चरित्र के लिए एक रैखिक स्कैन कर रहा है (समय से पहले एक सेट बनाने के लिए बेहतर है), और आप अनावश्यक रूप से एक सूची का निर्माण कर सकते हैं जब एक जनरेटर की समझ अधिक हल्की होगी।
ब्रायन

-1

यहाँ जेरब के "भोले दृष्टिकोण" पर आधारित कुछ है (भोले उनके शब्द हैं, मेरा नहीं!)।

import string
ALLOWED = frozenset(string.ascii_letters + string.digits + '_' + '-')

def check(mystring):
    return all(c in ALLOWED for c in mystring)

अगर ALLOWEDएक तार था, तो मुझे लगता है कि c in ALLOWEDजब तक यह एक मैच नहीं मिला या अंत तक नहीं पहुंचा, तब तक स्ट्रिंग में प्रत्येक चरित्र पर पुनरावृति शामिल होगी। जोएल स्पोल्स्की को उद्धृत करने के लिए, एक शलेमियल द पेंटर एल्गोरिथम का कुछ है

लेकिन एक सेट में अस्तित्व के लिए परीक्षण अधिक कुशल होना चाहिए, या अनुमत वर्णों की संख्या पर कम से कम निर्भर होना चाहिए। निश्चित रूप से यह दृष्टिकोण मेरी मशीन पर थोड़ा तेज है। यह स्पष्ट है और मुझे लगता है कि यह ज्यादातर मामलों के लिए पर्याप्त रूप से अच्छा प्रदर्शन करता है (मेरी धीमी मशीन पर मैं एक सेकंड के एक अंश में हजारों शॉर्ट-ईश स्ट्रिंग्स को मान्य कर सकता हूं)। मुझें यह पसंद है।

वास्तव में मेरी मशीन पर एक regexp कई बार तेजी से काम करता है, और यह इस तरह से सरल है (यकीनन सरल)। ताकि शायद आगे का सबसे अच्छा तरीका हो।


-4

एक regex का उपयोग करें और देखें कि क्या यह मेल खाता है!

([a-z][A-Z][0-9]\_\-)*

1
ये सभी वर्ण एक ही कक्षा में होने चाहिए, या आपको गलत नकारात्मक मिलेगा। इसके अलावा, आप शुरुआत-के-स्ट्रिंग और एंड-ऑफ-स्ट्रिंग मार्करों को शामिल करना भूल गए ... इस तरह, यह हमेशा मेल खाता रहेगा जब तक कि एक वैध चरित्र मौजूद है।
थॉमस

1
यह वास्तव में मैच होगा भले ही कोई वैध वर्ण न हो। शून्य लंबाई मैच। इसके अलावा, यह अजगर में नहीं है।
जेरुब
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.