2012-07-11 2 views
7

정규식을 사용하여 텍스트 블록에서 일부 내용을 삭제하려고합니다. 나는 모든 패턴을 준비했지만, 중복되는 두 개 (또는 그 이상)를 제거 할 수없는 것처럼 보입니다. 예를 들어여러 정규 표현식 대체하기

:

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을 사용합니다. 그것은 0 바이트로 초기화되고 모든 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

나는 match 객체의'start'와'end' 속성에 대해서는 생각해 본 적이 없습니다. 이게 효과가 있다는 것을 확신합니다. 감사합니다! – 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)? 

정규 표현식은 조립이 일치시킬으로 정규 표현식 또는 문자열의 모든 변종을 소요하고 하나에 그들을 결합.

$ 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 :: Assemble in python nice :)

+0

이 명령은'aptitude install libregexp-assemble-perl'입니다. 나는 당신이 지적한 이름으로 이전 패키지의 흔적을 빨리 찾을 수 없었지만 아마도 당신은 다른 배포판에있다. 이것은 데비안 안정입니다. – tripleee

+0

또한 패키지의 이전 버전에서는 데모가'/ usr/share/doc/libregexp-assemble-perl/examples/assemble.gz'에만있었습니다 -이 스크립트는'squeeze' 상자에 있어야합니다. 귀하가 지정한 이름과 함께 설치되지 않았습니다. – tripleee

1

선택자 반복자를 사용하여 텍스트에서 itertools.compress을 사용하여 즉석에서 문자열을 필터링하는 방법입니다. 문자를 보관해야하는 경우 selector는 True을 반환합니다. selector_for_patterns은 모든 패턴에 대해 하나의 선택기를 만듭니다. 선택기는 all 함수와 결합됩니다 (모든 패턴이 결과 문자열에 있어야하는 문자를 유지하려는 경우에만).

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