2012-07-11 18 views
7

मैं regex का उपयोग कर पाठ के ब्लॉक से कुछ चीजों को हटाने की कोशिश कर रहा हूं। मेरे पास मेरे सभी पैटर्न तैयार हैं, लेकिन मैं दो (या अधिक) को ओवरलैप करने में सक्षम नहीं हूं।एकाधिक रेगेक्स प्रतिस्थापन का संयोजन

उदाहरण के लिए:

import re 

r1 = r'I am' 
r2 = r'am foo' 

text = 'I am foo' 

re.sub(r1, '', text) # Returns ' foo' 
re.sub(r2, '', text) # Returns 'I ' 

मैं कैसे घटनाओं की दोनों एक साथ की जगह और कोई रिक्त स्ट्रिंग के साथ खत्म हो?


मैं Ned Batchelder's answer का एक थोड़ा संशोधित संस्करण का उपयोग कर समाप्त हो गया:

def clean(self, text): 
    mask = bytearray(len(text)) 

    for pattern in patterns: 
    for match in re.finditer(pattern, text): 
     r = range(match.start(), match.end()) 

     mask[r] = 'x' * len(r) 

    return ''.join(character for character, bit in zip(text, mask) if not bit) 

उत्तर

12

आप इसे दिखाए गए अनुसार re.sub कॉल के साथ ऐसा नहीं कर सकते हैं। आप उन्हें खोजने के लिए re.finditer का उपयोग कर सकते हैं। प्रत्येक मैच आपको एक मैच ऑब्जेक्ट प्रदान करेगा, जिसमें .start और .end गुण हैं जो उनकी स्थिति का संकेत देते हैं। आप उन सभी को एक साथ इकट्ठा कर सकते हैं, और फिर अंत में वर्ण हटा सकते हैं।

यहां मैं एक मुखौटा के रूप में उपयोग किए जाने वाले एक परिवर्तनीय स्ट्रिंग के रूप में bytearray का उपयोग करता हूं। इसे शून्य बाइट्स में शुरू किया गया है, और मैं किसी भी रेगेक्स से मेल खाने वाले सभी बाइट्स 'x' के साथ चिह्नित करता हूं। तब मैं केवल बेजोड़ पात्रों के साथ मूल स्ट्रिंग में रखने के लिए, और निर्माण के लिए एक नया स्ट्रिंग वर्ण का चयन करने के बिट मुखौटा का उपयोग करें:

bits = bytearray(len(text)) 
for pat in patterns: 
    for m in re.finditer(pat, text): 
     bits[m.start():m.end()] = 'x' * (m.end()-m.start()) 
new_string = ''.join(c for c,bit in zip(text, bits) if not bit) 
+0

मैंने मैच ऑब्जेक्ट्स के लिए 'स्टार्ट' और 'एंड' विशेषताओं के बारे में कभी सोचा नहीं। मुझे यकीन है कि यह काम करेगा, तो धन्यवाद! – Blender

+1

महान जवाब! मैंने '()' 'start' और 'end'' जोड़ा, क्योंकि ये विधियां हैं, विशेषता नहीं। – georg

+0

@ thg435: धन्यवाद, मुझे इसका परीक्षण करना चाहिए था! :) –

2

नहीं डाउनर होने के लिए, लेकिन संक्षिप्त उत्तर है कि मैं यकीन है कि आप नहीं कर सकते कर रहा हूँ। क्या आप अपना रेगेक्स बदल सकते हैं ताकि इसे ओवरलैपिंग की आवश्यकता न हो?

यदि आप अभी भी ऐसा करना चाहते हैं, तो मैं का ट्रैक रखने की कोशिश करता हूं, मूल स्ट्रिंग पर बने प्रत्येक मैच के सूचकांक को रोकें और रोकें। फिर स्ट्रिंग के माध्यम से जाएं और केवल अक्षरों को किसी भी विलोपन सीमा में न रखें?

1

काफी कुशल भी एक समाधान से ... पर्ल आ रहा है regexps गठबंधन एक में:

# aptitude install regexp-assemble 
$ regexp-assemble 
I am 
I am foo 
Ctrl + D 
I am(?: foo)? 

regexp-इकट्ठा regexps या स्ट्रिंग आप मैच के लिए की जाने वाली समस्त वेरिएंट लेता है और फिर उन्हें एक में गठबंधन। और हाँ यह एक और एक करने के लिए प्रारंभिक समस्या में परिवर्तन के बाद से यह अब और ओवरलैपिंग regexp मिलान, लेकिन एक मैच

के लिए regexp के संयोजन के बारे में नहीं है और फिर आप इसे अपने कोड में उपयोग कर सकते हैं:

$ python 
Python 2.7.3 (default, Aug 1 2012, 05:14:39) 
[GCC 4.6.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import re 
>>> re.sub("I am foo","I am(?: foo)?","") 
'' 

के एक बंदरगाह Regexp :: अजगर में इकट्ठा अच्छा होगा :)

+0

आदेश 'aptitude स्थापित libregexp-assemble-perl' है। मैं आपके द्वारा इंगित किए गए नाम के साथ पिछले पैकेज के किसी भी निशान को तुरंत नहीं ढूंढ सका, लेकिन हो सकता है कि आप एक अलग डिस्ट्रो पर हों; यह डेबियन स्थिर के लिए है। – tripleee

+0

इसके अलावा, पैकेज के पुराने संस्करणों में, डेमो केवल '/ usr/share/doc/libregexp-assemble-perl/example/assemble.gz' में था - मैं इसे' निचोड़ 'बॉक्स पर चाहता था, जहां स्क्रिप्ट आपके द्वारा इंगित नाम के साथ स्थापित नहीं है। – tripleee

1

यहां एक विकल्प है जो एक चयनकर्ता इटरेटर के साथ पाठ पर itertools.compress का उपयोग करके फ्लाई पर तारों को फ़िल्टर करता है। यदि चरित्र रखा जाना चाहिए तो चयनकर्ता True देता है। selector_for_patterns प्रत्येक पैटर्न के लिए एक चयनकर्ता बनाता है। चयनकर्ता सभी कार्यों के साथ संयुक्त होते हैं (केवल तभी जब सभी पैटर्न एक चरित्र रखना चाहते हैं, परिणामी स्ट्रिंग में होना चाहिए)।

import itertools 
import re 

def selector_for_pattern(text, pattern): 
    i = 0 
    for m in re.finditer(pattern, text): 
     for _ in xrange(i, m.start()): 
      yield True 
     for _ in xrange(m.start(), m.end()): 
      yield False 
     i = m.end() 
    for _ in xrange(i, len(text)): 
     yield True 

def clean(text, patterns): 
    gen = [selector_for_pattern(text, pattern) for pattern in patterns] 
    selector = itertools.imap(all, itertools.izip(* gen)) 
    return "".join(itertools.compress(text, selector)) 
संबंधित मुद्दे