2011-10-18 3 views
4

この質問はDjango URLリゾルバに由来しますが、問題は一般的な問題のようです。なぜ私のPythonの正規表現が複数のグループをチェックしているのですか?

私はこのように構築されたURLを一致させたい:

1,2,3,4,5,6/10,11,12/ 

私が使用している正規表現は次のとおりです。

^(?P<apples>([]+,?)+)/(?P<oranges>([]+,?)+)/$ 

私が「有効」URL(すなわちに対してそれと一致するようにしようとすると

In [11]: print datetime.datetime.now(); re.compile(r"^(?P<apples>([]+,?)+)/(?P<oranges>([]+,?)+)/$").search("114,414,415,416,417,418,419,420,113,410,411,412,413/1/"); print datetime.datetime.now() 
2011-10-18 14:27:42.087883 
Out[11]: <_sre.SRE_Match object at 0x2ab0960> 
2011-10-18 14:27:42.088145 

ただし、「無効な」URL(一致しないもの)と一致させようとすると、 、全体の正規表現は何も返さないために、時間の大きさを取る:

In [12]: print datetime.datetime.now(); re.compile(r"^(?P<apples>([]+,?)+)/(?P<oranges>([]+,?)+)/").search("114,414,415,416,417,418,419,420,113,410,411,412,413/"); print datetime.datetime.now() 
2011-10-18 14:29:21.011342 
2011-10-18 14:30:00.573270 

私はいくつかのグループが一致する必要がある場合に非常に遅くなる正規表現エンジンで何かがあると仮定します。このための回避策はありますか?たぶん私の正規表現を修正する必要がありますか?

答えて

5

これは、PythonやPerlを含む多くの正規表現エンジンでよく知られている欠点です。何が起こっているのは、エンジンがバックトラックして、可能な試合の指数関数的な爆発を試してみることです。より良い正規表現エンジンは、そのような単純な正規表現のためにバックトラッキングを使用しません。

オプションのカンマを削除することで修正できます。これは、エンジンが123のような文字列を見て、それを(123)または(12)(3)または(1)(23)または(1)(2)(3)として解析するかどうかを決定できるようにするものです。これは3桁の数字だけを試してみるためにたくさんの試合が行われているので、どのようにして数十桁の速さでかなり急速に爆発するか見ることができます。

^(?P<apples>[0-9]+(,[0-9]+)*)/(?P<oranges>[0-9]+(,[0-9]+)*)/$ 

この

は常にグループ 123,456 (123),(456)として、決して (12)(3),(4)(56)または何か他のもののように正規表現エンジンを行います。その方法でのみ一致するので、バックトラックエンジンは、可能な解析のコンビナトリアル爆発を打つことはありません。ここでも、より良い正規表現エンジンはこの欠陥に悩まされません。

アップデート:私はそれを書いていた場合、私はそれをこのようにします:

^(?P<apples>[0-9,]+)/(?P<oranges>[0-9,]+)$ 

「これは(,/,のような)いくつかの偽のURLを一致しますが、あなたはいつもあなたの後に404を返すことができますそれを解析してそれをルーティングしました。

try: 
    apples = [int(x) for x in apples.split(',')] 
except ValueError: 
    # return 404 error 
+0

REエンジンは言語の種類に少し少なく柔軟になりがち一致するが、彼ら受け入れてください。スタックベースのREエンジンは "いい" REを持っていればいいですが、オートマトンベースのREエンジンは "より厄介な" REを扱いますが、はるかに不思議な方法です。 (オートマトン理論のREエンジンに機能を追加するのは非常に難しい。なぜなら、すべてが相互作用する可能性があるすべての可能な方法に常に対処しなければならないからです。) –

+1

@DonalFellows:なぜREエンジンは、シンプルなREのためのオートマトンと、機能搭載のバックトラックエンジンを使用すべきですか?それはどちらの/または命題でもないので、私はそのような単純な正規表現のための節で声明を修飾するように注意していたのです。 –

+0

ありがとう、トリックでした! –

2

あなたはこの正規表現を使用できます。d \

^(?P<apples>(?:\d+,)*\d+)/(?P<oranges>(?:\d+,)*\d+)/$ 

は、この問題を持っていない桁

+0

私は実際にそれが属している正面に非オプションの数字を置くので、ディートリッヒの返答を好むが、あなたの答えはそれにもかかわらず正しい。私は1つしか受け入れることができないので、あなたはupvoteを得ています:) –

関連する問題