6

共通のロジックを持たないファイル名からいくつかの数値を解析する必要があります。「試してみれば許される」というPythonの方法、またはtry-except構造を使用したい。ここで、2 つ以上のケースを追加する必要があります。これを行う正しい方法は何ですか?私は今、入れ子になったtryか、try-except-pass、try-except-passのどちらかを考えています... どちらが良いですか、それとも何か他のものですか? おそらくファクトリーメソッド(どのように?)?

これは、より多くのケースがあるため、将来的に簡単に拡張できる必要があります。

以下は私が望むものです(試行ごとに1つの例外しか存在できないため、機能しません):

try:
    # first try
    imNo = int(imBN.split('S0001')[-1].replace('.tif',''))
except:
    # second try
    imNo = int(imBN.split('S0001')[-1].replace('.tiff',''))
except:
    # final try
    imNo = int(imBN.split('_0_')[-1].replace('.tif',''))

編集

うわー、答えてくれてありがとう、でもパターンマッチングはしないでください。私の悪い点は、最初に「いくつかの一般的なロジック」を入れてください(現在は「一般的なロジックなし」に変更されています。申し訳ありません)。上記の場合、パターンは非常に似ています...要点を明確にするために、まったく異なるものを追加させてください。

except:
    if imBN.find('first') > 0: imNo = 1
    if imBN.find('second') > 0: imNo = 2
    if imBN.find('third') > 0: imNo = 3
    ...
4

2 に答える 2

10

共通の構造を抽出して、可能なパラメーターのリストを作成できます。

tries = [
    ('S0001', '.tif'),
    ('S0001', '.tiff'),
    ('_0_', '.tif'),
]

for sep, subst in tries:
    num = imBN.split(sep)[-1].replace(subst, '')
    try:
        imNo = int(num)
        break
    except ValueError:
        pass
else:
    raise ValueError, "String doesn't match any of the possible patterns"

質問の編集に応じて更新

この手法は、ラムダを利用することで、任意の式に簡単に適用できます。

def custom_func(imBN):
    if 'first' in imBN: return 1
    if 'second' in imBN: return 2

tries = [
    lambda: int(imBN.split('S0001')[-1].replace('.tif','')),
    lambda: int(imBN.split('S0001')[-1].replace('.tiff','')),
    lambda: int(imBN.split('_0_')[-1].replace('.tif','')),
    lambda: custom_func(imBN),
]

for expr in tries:
    try:
        result = expr()
        break
    except:
        pass
else:
    # error
于 2012-04-25T14:36:03.503 に答える
3

特定のケースでは、正規表現を使用すると、これらの try-except ブロックを実行する必要がなくなります。このようなものがあなたのケースをキャッチするかもしれません:

>>> import re
>>> re.match('.*(S0001|_0_)([0-9]+)\..*$', 'something_0_1234.tiff').groups()
('_0_', '1234')
>>> re.match('.*(S0001|_0_)([0-9]+)\..*$', 'somethingS00011234.tif').groups()
('S0001', '1234')
>>> re.match('.*(S0001|_0_)([0-9]+)\..*$', 'somethingS00011234.tiff').groups()
('S0001', '1234')

シリアル try-except ブロックに関する質問については、Niklas B. の回答が明らかに優れています。

編集: あなたがしていることはパターンマッチングと呼ばれているので、パターンマッチングライブラリを使用してみませんか? 正規表現文字列が気になる場合は、よりクリーンな方法があります。

import re
matchers = []
sep = ['S0001', '_0_']
matchers.append(re.compile('^.*(' + '|'.join(sep) + ')(\d+)\..*$'))
matchers.append(some_other_regex_for_other_cases)

for matcher in matchers:
    match = matcher.match(yourstring)
    if match:
        print match.groups()[-1]

カスタム関数と互換性のある、より一般的な別の方法:

import re
matchers = []
simple_sep = ['S0001', '_0_']
simple_re = re.compile('^.*(' + '|'.join(sep) + ')(\d+)\..*$')
def simple_matcher(s):
    m = simple_re.match(s)
    if m:
        return m.groups()[-1]

def other_matcher(s):
    if s[3:].isdigit():
        return s[3:]

matchers.append(simple_matcher)
matchers.append(other_matcher)

for matcher in matchers:
    match = matcher('yourstring')
    if match:
        print int(match)
于 2012-04-25T14:55:11.903 に答える