2011-08-09 10 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 

はその後、私はマッチを探すために、次のコードを使用します。これらのPython正規表現を簡略化することは可能ですか?

 while matchFound(toSearch) > 0: 

私は、10種類の正規表現を持っていますが、私は彼らが、1に置き換えだけでなく、よりエレガントな正規表現を書くことができたような気がします。あなたはそれが可能だと思いますか?

EDIT:

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:TWO以上の式を忘れてしまった私は、次のようになってしまいました。私は余分な結果を得ることができたが、私は解析しているデータでは可能ではないと思います。

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

脇パターンから。P – Andrew

+1

複数の正規表現は、「これらのいずれかと一致するものを見つける」と言う場合は、常に1つの正規表現で置き換えることができます(* '*')。あなたの直感はここであなたによく役立っています。証明:正規表現を定義する文字列を '|'あなたはそれを構築しました。つまり、この場合、Seanはあなたのために私が説明したものをさらに単純化するものを作りました。 – Crisfole

+1

実際にあなたの質問に答えていない(私はSeanが既に行ったと信じています)私が使っているチートシートを推薦したいと思います。私は個人的には非常に珍しいregexpを使用しているので、私はいつもこのchetsheetに相談しています - http://www.addedbytes.com/cheat-sheets/regular-expressions-cheat-sheet/ - 私はそれが非常に便利だと思います。ただあなたのデスクのどこかにそれを印刷してください:) – Timur

答えて

4

ジョシュ・キャスウェルは、ショーン明るいの答えはあなたの元のグループよりも多くの入力と一致することに注意しました。申し訳ありませんが、私はこれを理解しませんでした。 (将来的には、あなたの問題を詳しく記入しておくと良いかもしれません。)

したがって、基本的な問題は数えられないということです。しかし、私たちはまだ非常に滑らかな方法でこれをPythonで解決できます。最初に、あなたの法的入力のいずれかと一致するパターンを作成しますが、あなたが拒絶したいパターンもあります。

次に、パターンを使用して一致オブジェクトを調べ、一致した文字列が長さの要件を満たしているかどうかを調べる関数を定義します。

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つの異なるセクションがあります。これらは「マッチグループ」になります。アルファベット文字と一致する2つの一致グループと、一致する2つの一致グループがあります。この1つのパターンは、あなたが望むすべてのものとマッチしますが、あなたが望まないものは除外しません。

次に、有効数字の長さがすべてsetであることを宣言します。たとえば、最初の数字のグループは1桁の長さになり、2番目のグループは2桁の数字になります。これは(1,2)tuple値)です。指定した長さのペアが合法であるかどうかを素早く確認できる一方で、合法的であると考えられる可能性のあるすべての組み合わせを指定するための素晴らしい方法です。

ファンクションcheck_match()は、文字列と一致するパターンを最初に使用し、mという名前にバインドされた「一致オブジェクト」を返します。検索が失敗した場合、mNoneに設定されている可能性があります。 Noneを明示的にテストする代わりに、try/exceptブロックを使用しました。振り返ってみると、ちょうどNoneをテストする方が良いかもしれません。申し訳ありませんが、私は混乱するつもりはありませんでした。しかし、try/exceptブロックは、何かをラップして非常に信頼できるものにする非常に簡単な方法です。

最後に、check_match()はマッチグループを4つの変数に展開します。 2つのアルファグループはa0とa1であり、2つのグループはn0とn1です。次に、長さが合法であることをチェックします。私が知る限り、アルファグループは同じ長さにする必要があります。番号グループの長さをtupleに設定して、tupleが有効であるtuplesetにあるかどうかを確認します。

ここでは、上記と少し異なるバージョンがあります。多分あなたはそれがより好きでしょう。

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

あなたが必要とする回答を与えました。ここに一般的なヒントがあります:

Pythonにはすばらしいドキュメントがあります。このケースでは、「ヘルプ」コマンドでそれを読むことができる:

import re 
help(re) 

そして、あなたが助けて読めば、次のように表示します:

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

それはまた、Googleを使用するのに役立ちます。 "Pythonの正規表現は、" 私のためにこれらのリンクを見つけました:

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

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

はどちらも読む価値があります。

+0

リンクありがとうございます。私は自分のお気に入りに追加します。 – anon58192932

1

Sean(今や明らかに削除された)回答に基づいて、パターンの数を減らすことができます。数字の一致の長さの組み合わせに制限があるため(つまり、最初の位置にあるmの場合は、少なくともmで、2番目の数字は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繰り返されることを指定{m,n}repeat qualifier syntax、しかし超えない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 
関連する問題