4

与えられた:

ABC
content 1
123
content 2
ABC
content 3
XYZ

「ABC[\W\w]+?XYZ」の最短バージョンに一致する正規表現を作成することは可能ですか?

基本的に、私は「ABC の後に XYZ で終わる任意の文字が続きますが、間に ABC があると一致しません」を探しています (ただし、ABC は常に設定された長さであるとは限らないため、潜在的な正規表現自体と考えてください。 ..したがって、ABC または ABcC も一致する可能性があります)

したがって、より一般的には、REGEX1 の後に任意の文字が続き、REGEX2 で終了します。REGEX1 が間にある場合は一致しません。

この例では、最初の 4 行は必要ありません。

(この説明には潜在的に必要な可能性があると確信しています...さらに説明が必要です笑)

編集:

よし、これでさらに説明が必要だ!これまでの提案に感謝します。提案された各ソリューションを私の問題にどのように適用できるかを調べ始める間、少なくとも考えるべきことをすべて提供します.

提案 1:文字列の内容と正規表現を逆にします。

これは確かに、私が説明したことに基づいて問題を解決する非常に楽しいハックです。問題を単純化する際に、終了署名が後で存在する可能性があるため、同じことが逆に発生する可能性があることにも言及しませんでした(そして、私の特定の状況にあることが証明されています). これにより、以下に示す問題が発生します。

ABC
content 1
123
content 2
ABC
content 3
XYZ
content 4
MNO
content 5
XYZ

この例では、[ABC、コンテンツ 1、XYZ] をキャッチすることを意味する「XYZ を介して ABC」のようなものをチェックします...しかし、誤って [ABC、コンテンツ 1、123、コンテンツ 2、ABC、コンテンツ 3、XYZ] をキャッチします。 . これを逆にすると、再度必要な [ABC、コンテンツ 2、XYZ] の代わりに [ABC、コンテンツ 3、XYZ、コンテンツ 4、MNO、コンテンツ 5、XYZ] がキャッチされます。ポイントは、可能な限り一般化することです。これは、同じ開始署名 (この場合は正規表現 "ABC") と異なる終了署名を持つ可能性があるものも検索するためです。

この種の制限をカプセル化するように正規表現を作成する方法があれば、カスタム検索アルゴリズムを作成するよりも、このタイプの文字列で検索する正規表現を作成するときはいつでもそれを参照する方がはるかに簡単であることがわかります。それを扱います。

提案 2: A+B+C+[^A]+[^B]+[^C]+XYZ IGNORECASE フラグ付き

これは、ABC が有限である場合には良さそうです。ただし、それ自体を正規表現と考えてください。例えば:

Hello!GoodBye!Hello.Later.

私がやろうとしていることの非常に単純化されたバージョン。「Hello.Later」が欲しいです。開始の正規表現 Hello[!.] と終了の Later[!.]. Hello[!.]Later[!.] のような単純なものを実行すると、文字列全体が取得されますが、開始正規表現 Hello[!.] が見つかった最初の開始正規表現インスタンスと最初の終了正規表現の間に存在する場合、インスタンスが見つかりましたが、無視してください。

この提案の下の会話は、括弧の一致の問題と同様に、通常の言語の制限によって制限される可能性があることを示しています (Google で検索してみてください。考えるのは楽しいです)。この投稿の目的は、私が実際に直面している問題を処理する基本的なアルゴリズムを作成する必要があるかどうかを確認することです。可能であれば、それを避けたいと思います(上記の単純な例では、有限状態マシンを設計するのは非常に簡単です...少し複雑になってもそれが維持されることを願っています)。

提案 3: ABC(?:(?!ABC).)*?XYZ with DOTALL フラグ

実際に ABC を正規表現にできるのであれば、このアイデアが気に入っています。明日オフィスに着いたら、これを調べなければなりません。一見、異常なことは何もないように見えますが、私は Python 正規表現にまったく慣れていません (そして、理論上の宿題ではなく、実際に正規表現をコードに適用するのも初めてです)。

4

3 に答える 3

7

正規表現の解決策はABC(?:(?!ABC).)*?XYZDOTALLフラグを使用することです。

于 2012-06-12T01:06:22.447 に答える
1

編集

したがって、あなたのさらなる説明を読んだ後、私の以前の提案と MRAB の提案は何らかの形で類似しており、ここでは役に立たないと思います。あなたの問題、実際にはネストされた構造の問題です。

「接頭辞」と「接尾辞」は記号と考えてください。それらを開き括弧と閉じ括弧などに簡単に置き換えることができ、必要なのは最小の(そして最も深い)ペアのみに一致できることです...

たとえば、プレフィックスが「ABC」の場合。接尾辞は「XYZ.」です。

ABChello worldABCfooABCbarXYZ

のみを取得しますABCbarXYZ

接頭辞が(、接尾辞が)、文字列の場合も同じです。

(hello world(foo(bar)

理想的には一致し(bar)ます...

間違いなく、文脈自由文法(プログラミング言語が行うように: C grammarPython grammar ) とパーサーを使用するか、プログラミング言語の反復および保存メカニズムと同様に正規表現を使用して独自のものを作成する必要があります。

しかし、それは正規表現だけでは不可能です。それらはおそらくあなたのアルゴリズムに役立つでしょうが、それを単独で処理するようには設計されていません. その仕事には適したツールではありません...ドライバーでタイヤに空気を入れることはできません。したがって、複雑ではありませんが、コンテキスト、ネストされたスタック内の位置を保存するために、いくつかの外部メカニズムを使用する必要があります。単一のコンテキストごとに正規表現を使用することはまだ可能かもしれません。

有限状態マシン有限であり、ネストされた構造には任意の深さがあるため、オートマトンを任意に成長させる必要があるため、通常の言語ではありません。

文法における再帰はネストされた構文構造の定義を可能にするので、ネストされた構造を許容するすべての言語 (プログラミング言語を含む) は、通常の言語ではなく、文脈自由言語です。たとえば、[英数字を削除した LISP プログラムのような] バランスの取れた括弧で構成される文字列のセットは、文脈自由言語です 。こちらを参照してください。

以前の提案 (もはや関係ありません)

私が行った場合:

>>> s = """ABC
content 1
123
content 2
ABC
content 3
XYZ"""
>>> r = re.compile(r'A+B+C+[^A]+[^B]+[^C]+XYZ', re.I)
>>> re.findall(r,s)

私は得る

['ABC\ncontent 3\nXYZ']

それはあなたが望むものですか?

于 2012-06-12T01:05:51.133 に答える
0

この問題を解決する別の方法があります: 1 つの正規表現で解決しようとしないことです。最初の正規表現で文字列を分割し、最後の部分で 2 番目の正規表現を使用できます。

コードは最良の説明です:

s = """ABC
content 1
123
content 2
ABC
content 3
XYZ
content 4
XYZ"""

# capturing groups to preserve the matched section
prefix = re.compile('(ABC)')
suffix = re.compile('(XYZ)')

# prefix.split(s) == ['', 'ABC', [..], 'ABC', '\ncontent 3\nXYZ\ncontent 4\nXYZ']
#                          prefixmatch ^^^^^  ^^^^^^^^^^^^ rest ^^^^^^^^^^^^^^^^
prefixmatch, rest = prefix.split(s)[-2:]

# suffix.split(rest,1) == ['\ncontent 3\n', 'XYZ', '\ncontent 4\nXYZ']
#                          ^^ interior ^^   ^^^^^ suffixmatch
interior, suffixmatch = suffix.split(rest,1)[:2]

# join the parts up.
result = '%s%s%s' % (prefixmatch, interior, suffixmatch)

# result == 'ABC\ncontent 3\nXYZ'

いくつかのポイント:

  • try: ... except ValueError: ..いずれかの正規表現がまったく一致せず、リストのアンパックが失敗する場合を処理するために、適切なエラー処理 (全体の周りであっても) が必要です。
  • これは、目的のセグメントが の最後の発生の直後に発生すると想定していますprefix。そうでない場合はprefix.split(s)、一度に 2 つの結果を反復処理し (インデックス 1 から開始)、 で同じ分割トリックを実行しsuffixて、すべての一致を見つけることができます。
  • かなりの数の中間データ構造が作成されるため、これはかなり非効率的である可能性があります。
于 2012-06-12T12:16:21.097 に答える