5

テキストのページからデータを抽出するために複雑な正規表現を設定しました。何らかの理由で、交互の順序が期待どおりではありません。簡単な例は次のとおりです。

((13th|(Executive |Residential)|((\w+) ){1,3})Floor)

簡単に言えば、フロア番号、既知の名前の付いたフロアを取得しようとしており、バックアップとして、後で確認する場合に備えて、1 ~ 3 個の不明な単語とフロアをキャプチャします (実際にはグループ名を使用してこれを識別します)。しかし、問題を混乱させたくありませんでした)

問題は、文字列が

on the 13th Floor

3番目のオルタネーションと一致していることを示しているように見えます13th Flooron the 13th Floor13階に合うと思っていたのに。私はこれを具体的に (または私が考えたように) マッチのタイプに優先順位を付け、他のマッチが見逃された場合にのみあいまいなものを最後に残すように設定しました。正規表現が貪欲であると言ったとき、彼らは冗談ではなかったと思いますが、これを「貪欲」に設定して、私が望むように動作させる方法がわかりません。

4

2 に答える 2

5

オートマトンは 1000 語に値します。

正規表現の視覚化

それで遊びます

あなたの問題は\w+、交互に貪欲なサブ正規表現を使用していることです。@rigderunner がコメントで述べているように、NFA は最も左端の部分文字列に一致するため、一連の単語であろうと、またはそれらの3 つであろうと、\w+は常に の前にあるものと一致します。括弧は、交互の動作を変更していません。Floor13thExecutiveResidential

したがって、一致させたくない最悪のケースのシナリオは次のとおりです。

xxxx yyyy zzz tttt Floor

正規表現の問題は、実際の正規表現ではできないことを期待していることです。代替手段がうまくいかなかった場合に、単語と一致することを期待しています。通常の言語ではステータスを追跡できないため、通常正規表現ではこれを表現できません。

ある種の先読みを使用してこれを1つの正規表現で実行できるかどうかは実際にはわかりません。たとえできたとしても、非常に複雑で判読できず、おそらく効率的ではない正規表現になってしまうでしょう。

そのため、代わりに 2 つの正規表現を使用し、最初の正規表現が失敗した場合に備えて 2 番目の正規表現からグループを取得することをお勧めします。

((13th|Executive|Residential) +Floor)

一致しない場合

((\w+ +){1:3}Floor)

注意: 繰り返しを避けるために、正規表現と NFA について講義している興味深いリソースのリストを提供している他の回答をご覧ください。これは、正規表現が実際にどのように機能するかを理解するのに役立ちます。

于 2014-05-21T12:29:49.467 に答える
3

まず、フリースペースモードでの正規表現は次のとおりです。

tidied = re.compile(r"""
    (                   # $1: ...
      (                 # $2: One ... from 3 alternatives.
        13th            # Either a1of3.
      | (               # Or a2of3 $3: One ... from 2 alternatives.
          Executive[ ]  # Either a1of2.
        | Residential   # Or a2of2.
        )               # End $3: One ... from 2 alternatives.
      | (               # Or a3of3 $4: Last match from 1 to 3 ...
          (\w+)         # $5: ...
          [ ]           #
        ){1,3}          # End $4: Last match from 1 to 3 ...
      )                 # End $2: One ... from 3 alternatives.
      Floor             #
    )                   # End $1: ...
    """, re.VERBOSE)

上記のパターンには、効果のない余分な括弧があることに注意してください。機能的に同等の単純化された式を次に示します。

tidied = re.compile(r"""
    (               # $1: One ... from 4 alternatives.
      13th          # Either a1of4.
    | Executive[ ]  # Or a2of4.
    | Residential   # Or a3of4.
    | (             # Or a4of4 $2: Last match from 1 to 3 ...
        (\w+)       # $3: ...
        [ ]         #
      ){1,3}        # End $2: Last match from 1 to 3 ...
    )               # End $1: One ... from 4 alternatives.
    Floor           #
    """, re.VERBOSE)

最長の左端の一致

必要な単語の前に、事実上 4 つのグループ化された選択肢がありますFloor。最初の 3 つの選択肢はそれぞれ 1 単語のみですが、4 番目の選択肢は 3 つの単語に一致します。NFA 正規表現エンジンは左から右に動作し、常に左端の最長の一致を見つけようとします。この場合、正規表現は一度に 1 文字ずつ正規表現を実行するため、各文字位置で 4 つのオプションすべてをテストします。4 番目のオプションは、他の 3 つの単語よりも 2 つ前の単語に常に一致する可能性があるため、常に最初に一致します (Floor指定されたテキストの前に 3 つの単語があると仮定します)。の前に 3 つの単語がない場合Floor、最初の 3 つの選択肢のいずれかが一致します。

13thandの選択肢の後に必要なスペースがないことにも注意してくださいResidential。したがって、連結されたテキストを含むテキストが提示された場合にのみ一致します: ResidentialFlooror 13thFloor.

于 2014-05-21T13:08:01.273 に答える