2011-08-09 3 views
2
patterns = {} 
    patterns[1] = re.compile("[A-Z]\d-[A-Z]\d") 
    patterns[2] = re.compile("[A-Z]\d-[A-Z]\d\d") 
    patterns[3] = re.compile("[A-Z]\d\d-[A-Z]\d\d") 
    patterns[4] = re.compile("[A-Z]\d\d-[A-Z]\d\d\d") 
    patterns[5] = re.compile("[A-Z]\d\d\d-[A-Z]\d\d\d") 
    patterns[6] = re.compile("[A-Z][A-Z]\d-[A-Z][A-Z]\d") 
    patterns[7] = re.compile("[A-Z][A-Z]\d-[A-Z][A-Z]\d\d") 
    patterns[8] = re.compile("[A-Z][A-Z]\d\d-[A-Z][A-Z]\d\d") 
    patterns[9] = re.compile("[A-Z][A-Z]\d\d-[A-Z][A-Z]\d\d\d") 
    patterns[10] = re.compile("[A-Z][A-Z]\d\d\d-[A-Z][A-Z]\d\d\d") 

    def matchFound(toSearch): 
     for items in sorted(patterns.keys(), reverse=True): 
      matchObject = patterns[items].search(toSearch) 
      if matchObject: 
       return items 
     return 0 

는 내가 일치를 찾기 위해 다음 코드를 사용이 파이썬 정규 표현식을 단순화 할 수 있습니까?

 while matchFound(toSearch) > 0: 

나는 10 개의 정규 표현식을 가지고 있지만 나는 그들이 하나의 대체 잘, 더 우아한 정규 표현식을 작성할 수 있습니다 같은 느낌. 너희들이 가능하다고 생각하니?

편집 : 나는 다음과 결국 :

patterns[11] = re.compile("[A-Z]\d-[A-Z]\d\d\d") 
    patterns[12] = re.compile("[A-Z][A-Z]\d-[A-Z][A-Z]\d\d\d") 

EDIT2 : 두 개 더 표현을 잊어 버렸습니다. 내가 추가 결과를 얻을 수 있을지는 모르겠지만 파싱 할 데이터에서 가능하지 않다고 생각합니다.

patterns = {} 
    patterns[1] = re.compile("[A-Z]{1,2}\d-[A-Z]{1,2}\d{1,3}") 
    patterns[2] = re.compile("[A-Z]{1,2}\d\d-[A-Z]{1,2}\d{2,3}") 
    patterns[3] = re.compile("[A-Z]{1,2}\d\d\d-[A-Z]{1,2}\d\d\d") 
+1

.join ('|') 나는 다음과 같이 추정한다 : P – Andrew

+1

"이것들과 일치하는 것을 찾는다"고 말하기를 원한다면 여러 개의 정규 표현식을 항상 하나의 정규 표현식으로 바꿀 수있다. 당신의 직감이 여기에서 당신을 잘 돕고 있습니다. 증명 : 정규식을 정의하는 문자열을 '|' 당신은 그것을 구성했습니다. 즉,이 경우 Sean은 내가 방금 설명한 내용을 더 단순화 한 것을 제작했습니다. – Crisfole

+1

실제로 귀하의 질문에 대답하지 않습니다 (저는 Sean이 이미 한 것으로 믿습니다). 나는 사용하는 속임수 시트를 추천하고 싶습니다. 나는 개인적으로 꽤 희귀 한 regexp를 사용한다. 그래서 나는 항상이 chetsheet와 상담한다 - http://www.addedbytes.com/cheat-sheets/regular-expressions-cheat-sheet/ - 나는 그것을 매우 유용하다고 느낀다. 그냥 책상 밖으로 어딘가에 그것을 밖으로 인쇄하십시오 :) – Timur

답변

4

조쉬 캐스 웰은 숀 밝은의 대답은 원래 그룹보다 더 많은 입력을 일치 지적했다. 미안해. 이걸 알아 내지 못했어. (장래에 문제를 조금 더 자세히 설명하는 것이 좋습니다.)

그래서 기본적인 문제는 중요하지 않다는 것입니다. 그러나 우리는 여전히 매우 매끄러운 방식으로 파이썬에서이를 해결할 수 있습니다. 먼저 법적인 입력 내용과 일치하는 패턴을 만들지 만 거부하려는 패턴과 일치시킵니다.

다음으로 패턴을 사용하는 함수를 정의한 다음 일치 객체를 검사하고 일치하는 문자열이 길이 요구 사항을 충족하는지 확인합니다.

import re 
_s_pat = r'([A-Z]{1,2})(\d{1,3})-([A-Z]{1,2})(\d{1,3})' 
_pat = re.compile(_s_pat) 

_valid_n_len = set([(1,1), (1,2), (1,3), (2,2), (2,3), (3,3)]) 
def check_match(s): 
    m = _pat.search(s) 
    try: 
     a0, n0, a1, n1 = m.groups() 
     if len(a0) != len(a1): 
      return False 
     if not (len(n0), len(n1)) in _valid_n_len: 
      return False 
     return True 
    except (AttributeError, TypeError, ValueError): 
     return False 

다음은 위의 코드에 대한 설명입니다.

먼저 패턴을 정의하기 위해 원시 문자열을 사용하고 패턴을 미리 컴파일합니다. 우리는 re.compile()에 대한 호출에 리터럴 문자열을 채울 수는 있지만 별도의 문자열을 갖고 싶어합니다. 우리 패턴에는 괄호 안에 4 개의 뚜렷한 섹션이 있습니다. 이들은 "일치 그룹"이됩니다. 알파벳 문자와 일치하는 두 개의 일치 그룹과 숫자와 일치하는 두 개의 일치 그룹이 있습니다. 이 패턴은 당신이 원하는 모든 것을 일치 시키지만 원하지 않는 것들은 제외시키지 않을 것입니다.

다음으로 숫자에 대해 유효한 길이가 모두있는 set을 선언합니다. 예를 들어, 첫 x 째 그룹은 1 자릿수이고 두 x 째 그룹은 2 자릿수가 될 수 있습니다. 이 값은 (1,2) (tuple 값)입니다. 세트는 주어진 합당한 길이의 쌍이 합법적인지 신속하게 확인할 수있는 동시에 합법적 인 모든 가능한 조합을 지정하는 좋은 방법입니다.

함수 check_match()은 문자열과 일치하는 패턴을 먼저 사용하여 m이라는 이름으로 바인딩 된 "일치 개체"를 반환합니다. 검색에 실패하면 mNone으로 설정 될 수 있습니다. 명시 적으로 None을 테스트하는 대신 try/except 블록을 사용했습니다. 되돌아 보면 None을 테스트하는 것이 더 나았을 것입니다. 죄송합니다. 혼란 스러울 의도는 없었습니다. 그러나 try/except 블록은 무언가를 랩핑하고 매우 신뢰할 수있게 만드는 아주 간단한 방법이므로, 나는 종종 이런 식으로 사용합니다.

마지막으로 check_match()은 일치 그룹을 4 개의 변수로 압축 해제합니다. 두 개의 알파 그룹은 a0과 a1이고 두 개의 숫자 그룹은 n0과 n1입니다. 그런 다음 길이가 합법적인지 확인합니다. 내가 알 수있는 한, 규칙은 알파 그룹이 동일한 길이 일 필요가 있다는 것입니다. 번호 그룹 길이가 tuple 인 것을 확인하고 tupletupleset에 있는지 확인합니다.

위와 약간 다른 버전입니다. 어쩌면 당신은 그것을 더 좋아할 것입니다.

import re 
# match alpha: 1 or 2 capital letters 
_s_pat_a = r'[A-Z]{1,2}' 
# match number: 1-3 digits 
_s_pat_n = r'\d{1,3}' 

# pattern: four match groups: alpha, number, alpha, number 
_s_pat = '(%s)(%s)-(%s)(%s)' % (_s_pat_a, _s_pat_n, _s_pat_a, _s_pat_n) 
_pat = re.compile(_s_pat) 

# set of valid lengths of number groups 
_valid_n_len = set([(1,1), (1,2), (1,3), (2,2), (2,3), (3,3)]) 

def check_match(s): 
    m = _pat.search(s) 
    if not m: 
     return False 
    a0, n0, a1, n1 = m.groups() 
    if len(a0) != len(a1): 
     return False 
    tup = (len(n0), len(n1)) # make tuple of actual lengths 
    if not tup in _valid_n_len: 
     return False 
    return True 

참고 : 그것은 유효 길이에 대한 규칙처럼 보인다는 사실 간단하다 : 그 규칙이 당신을 위해 작동

if len(n0) > len(n1): 
     return False 

경우, 세트와 튜플 물건을 제거 할 수있다. 흠, 나는 변수 이름을 좀 더 짧게 만들 것이다.

import re 
# match alpha: 1 or 2 capital letters 
pa = r'[A-Z]{1,2}' 
# match number: 1-3 digits 
pn = r'\d{1,3}' 

# pattern: four match groups: alpha, number, alpha, number 
p = '(%s)(%s)-(%s)(%s)' % (pa, pn, pa, pn) 
_pat = re.compile(p) 

def check_match(s): 
    m = _pat.search(s) 
    if not m: 
     return False 
    a0, n0, a1, n1 = m.groups() 
    if len(a0) != len(a1): 
     return False 
    if len(n0) > len(n1): 
     return False 
    return True 
+0

오, 당신은 나보다 약간 빠릅니다 :-) 그것은 정확히 내가 의미했던 것입니다. – glglgl

+0

이것은 좋아 보이지만 나는이 코드가 무엇을하는지 전혀 모르겠다. 편집 : 코드를 조금 읽은 후에 알았어. 알았어. 고마워. 고마워. – anon58192932

+0

미안하지만 나는 애매한 것이 아닙니다. 코드 뒤에 몇 가지 설명을 추가하겠습니다. – steveha

4

숀 브라이트 (Sean Bright)가 필요한 답변을 주셨습니다. 다음은 일반적인 팁입니다.

Python에 멋진 문서가 있습니다.

import re 
help(re) 

을 그리고 당신이 도움을 읽는다면, 당신은 볼 것이다 :이 경우, "도움말"명령을 읽을 수 또한 구글을 사용하는 데 도움이

{m,n} Matches from m to n repetitions of the preceding RE. 

합니다. "파이썬 정규 표현식은"나를 위해 이러한 링크를 발견 :

http://docs.python.org/library/re.html

http://docs.python.org/howto/regex.html

는 모두 읽을 가치가있다.

+0

링크 주셔서 감사합니다. 나는 그들을 내 즐겨 찾기에 추가 할 것이다. – anon58192932

1

Sean (지금 명백하게 삭제 된) 답변을 바탕으로 패턴 수를 줄일 수 있습니다. 숫자 맞추기 길이의 조합에 대한 제한 때문에 (즉, 첫 번째 위치에 m 인 경우 적어도 m이고 두 번째 숫자는 3을 넘지 않음) 다음 중 하나를 얻을 수 있는지 확실하지 않습니다.

"[A-Z]\d-[A-Z]\d{1,3}" 
"[A-Z]\d\d-[A-Z]\d{2,3}" 
"[A-Z]\d\d\d-[A-Z]\d\d\d" 
"[A-Z][A-Z]\d-[A-Z][A-Z]\d{1,3}" 
"[A-Z][A-Z]\d\d-[A-Z][A-Z]\d{2,3}" 
"[A-Z][A-Z]\d\d\d-[A-Z][A-Z]\d\d\d" 

여기에는 {m,n}repeat qualifier syntax이 사용되며, 바로 앞의 일치가 적어도 m이지만, n 번 이상 반복되지 않도록 지정합니다. 단일 번호 n을 지정할 수도 있습니다. 다음 경기는 정확히 n 번 성공해야합니다

"[A-Z]{2}\d-[A-Z]{2}\d{2,3}" 
+0

이것은 내가 가지고있는 것보다 훨씬 낫습니다. 그러나 그것은 또한 나의 코드에서 논리적 오류를 조명했다. 나는 그 질문을 편집 할 것이다. – anon58192932

3

조쉬는 최소한 RE의 수를 줄이는 것이 옳습니다.

그러나 허용되는 것보다 넓은 RE를 취하여 모든 조건이 충족되는지 여부도 추가로 확인할 수 있습니다. 이러한

pattern = re.compile("([A-Z]{1,2})(\d{1,3})-([A-Z]{1,2})(\d{1,3})") 

하고 다음

matchObject = pattern.search(toSearch) 
if matchObject and <do something with the length of the groups, comparing them)>: 
    return <stuff> 

그러나 어떤 이유 때문에 작동하지 않는 경우에도, 그것을 개선 할 수있는 방법이 있습니다 : 패턴에서 제외

patterns = tuple(re.compile(r) for r in (
    "[A-Z]\d-[A-Z]\d{1,2}", 
    "[A-Z]\d\d-[A-Z]\d{2,3}", 
    "[A-Z]\d\d\d-[A-Z]\d\d\d", 
    "[A-Z][A-Z]\d-[A-Z][A-Z]\d{1,2}", 
    "[A-Z][A-Z]\d\d-[A-Z][A-Z]\d{2,3}", 
    "[A-Z][A-Z]\d\d\d-[A-Z][A-Z]\d\d\d", 
) 

def matchFound(toSearch): 
    for pat in reversed(patterns): 
     matchObject = pat.search(toSearch) 
     if matchObject: 
      return items # maybe more useful? 
    return None 
관련 문제