2009-09-03 4 views
22

में एक स्ट्रिंग में रेगेक्स मैचों की कितनी बार पता लगाएं कि क्या कोई तरीका है कि मैं पाइथन में स्ट्रिंग में कितने मैचों का पता लगा सकता हूं? उदाहरण के लिए, अगर मैं स्ट्रिंग "It actually happened when it acted out of turn."पाइथन

है मुझे पता है कि कितनी बार "t a" स्ट्रिंग में प्रकट होता है चाहता हूँ। उस स्ट्रिंग में, "t a" दो बार प्रकट होता है। मैं चाहता हूं कि मेरा कार्य मुझे बताए कि यह दो बार दिखाई देता है। क्या यह संभव है?

+0

क्या आपको ओवरलैपिंग मैचों की गणना करने की आवश्यकता है? क्या एक दोस्त के दोस्त "दोस्त के दोस्त" दोस्त में एक या दो बार "दोस्त का मित्र" है? –

+0

मुझे ओवरलैपिंग की आवश्यकता है। – Dan

+2

आपको ओवरलैपिंग की आवश्यकता है? इसलिए, यदि मिलान पैटर्न "aa" है और स्रोत स्ट्रिंग "aaaa" सही उत्तर 3 है? – steveha

उत्तर

16

मौजूदा समाधान के गैर-अतिव्यापी घटनाओं पर findall आधारित की संख्या लौट गैर-अतिव्यापी मैचों के लिए ठीक हैं (और शायद मैचों की भारी संख्या के अलावा कोई संदेह नहीं है इष्टतम), हालांकि sum(1 for m in re.finditer(thepattern, thestring)) जैसे विकल्प (सूची की भौतिकता को हमेशा से बचाने के लिए जब आप जिनकी परवाह है, वे भी गिनती हैं) भी काफी संभव हैं। कुछ हद तक विशेष स्वभाव का subn का उपयोग कर किया जाएगा और जिसके परिणामस्वरूप स्ट्रिंग अनदेखी ...:

def countnonoverlappingrematches(pattern, thestring): 
    return re.subn(pattern, '', thestring)[1] 

बाद इस विचार का केवल वास्तविक लाभ अगर आप केवल (मान) की गणना करने के लिए 100 मैचों अप करने के लिए परवाह आएगा; फिर, re.subn(pattern, '', thestring, 100)[1] व्यावहारिक हो सकता है (100 लौट रहा है चाहे 100 मैचों, या 1000, या यहां तक ​​कि बड़ी संख्याएं हों)।

गिनती मैचों की ओवरलैपिंग आपको अधिक कोड लिखने की आवश्यकता है, क्योंकि प्रश्न में अंतर्निहित कार्य सभी गैर-ओवरलैपिंग मैचों पर केंद्रित हैं। परिभाषा की एक समस्या भी है, उदाहरण के साथ, पैटर्न 'a+' और स्ट्रिंग 'aa' होने के साथ, क्या आप इसे केवल एक मैच, या तीन (पहले a, दूसरा, दोनों), या ... के रूप में मानेंगे?

उदाहरण है कि आप संभवतः को लेकर टकराव पैदा करना चाहते हैं स्ट्रिंग में अलग धब्बे (जो तब पिछले पैराग्राफ में उदाहरण के लिए दो मैचों देना होगा) पर शुरू मैचों के लिए मान लिया जाये:

def countoverlappingdistinct(pattern, thestring): 
    total = 0 
    start = 0 
    there = re.compile(pattern) 
    while True: 
    mo = there.search(thestring, start) 
    if mo is None: return total 
    total += 1 
    start = 1 + mo.start() 

नोट आप करते हैं कि इस मामले में पैटर्न को आरई ऑब्जेक्ट में संकलित करना होगा: फ़ंक्शन re.search तर्क (खोज के लिए प्रारंभ करने की स्थिति) को विधिsearch करता है, इसलिए आपको स्ट्रिंग को स्लाइसिंग करना होगा - अगली खोज होने की तुलना में निश्चित रूप से अधिक प्रयास अगले संभावित विशिष्ट प्रारंभ बिंदु पर टार्ट, जो मैं इस समारोह में कर रहा हूं।

6

क्या आपने यह कोशिश की है?

len(pattern.findall(source)) 
+1

यह खोज है हालांकि – cobbal

+0

इसे ठीक करने के लिए धन्यवाद! –

+0

क्या यह गिनती अतिव्यापी है? उन्होंने कहा कि इसे समर्थन देने की जरूरत है। (ऐसा लगता है कि प्रदर्शन करना वास्तव में मुश्किल होगा) –

30
import re 
len(re.findall(pattern, string_to_search)) 
+0

ग्रेट जॉब !!! धन्यवाद –

0
import re 
print len(re.findall(r'ab',u'ababababa')) 
9

मैं जानता हूँ कि इस regex के बारे में एक सवाल है। मैंने सोचा कि अगर भविष्य में कोई गैर-रेगेक्स समाधान चाहता है तो मैं भविष्य में संदर्भ के लिए count विधि का उल्लेख करूंगा।

>>> s = "It actually happened when it acted out of turn." 
>>> s.count('t a') 
2 

कौन-स्ट्रिंग

5

आप एक noncapturing subpattern का उपयोग करके मैचों ओवरलैपिंग पा सकते हैं:

def count_overlapping(pattern, string): 
    return len(re.findall("(?=%s)" % pattern, string)) 
0

मैचों की एक सूची बनाने के एक भी स्थानापन्न के रूप में एक प्रतिदेय साथ re.sub उपयोग कर सकते हैं से बचने के लिए। यह प्रत्येक काउंटर पर कॉल किया जाएगा, आंतरिक काउंटर में वृद्धि होगी।

class Counter(object): 
    def __init__(self): 
     self.matched = 0 
    def __call__(self, matchobj): 
     self.matched += 1 

counter = Counter() 
re.sub(some_pattern, counter, text) 

print counter.matched