web-dev-qa-db-ja.com

PythonのPerl互換正規表現(PCRE)

PythonのPCREに基づいていくつかの文字列を解析する必要がありますが、その方法がわかりません。

解析したい文字列は次のようになります。

match mysql m/^.\0\0\0\n(4\.[-.\w]+)\0...\0/s p/MySQL/ i/$1/

この例では、次のさまざまなアイテムを取得する必要があります。

"m/^.\0\0\0\n(4\.[-.\w]+)\0...\0/s" ; "p/MySQL/" ; "i/$1/"

PythonでのPCRE操作に関連して私が見つけた唯一のものはこのモジュールです: http://pydoc.org/2.2.3/pcre.html (しかし書かれているのは.soファイルです...)

この種の文字列を解析するためのPythonモジュールが存在するかどうか知っていますか?

29
Steeve

Pythonでは非ASCIIに特に注意してください

Pythonがパターンや文字列の非ASCIIを処理する方法、または処理に失敗する方法には、非常に微妙な問題がいくつかあります。さらに悪いことに、これらの不一致は、=のバージョンだけでなく、大幅に異なります。 Python使用しているだけでなく、「ワイドビルド」があるかどうか。

一般に、Unicodeを使用している場合、ワイドビルドのPython 3が最適に機能し、ナロービルドのPython 2が最悪に機能しますが、すべての組み合わせPerl正規表現がどのように機能するかvis-à-visUnicodeとはまだかなりかけ離れています。 Pythonでᴘᴄʀᴇパターンを探している場合は、古いreモジュールよりも少し遠くを探す必要があるかもしれません。

厄介な「ワイドビルド」の問題は、最終的に修正されました-あなたが使用する場合Pythonの十分に高度なリリース。 v3.3リリースノート からの抜粋です。

機能性

PEP 39 によって導入された変更は次のとおりです。

  • Pythonは、BMP以外のコードポイント(つまり、U +0000からU + 10FFFF)を含むすべてのUnicodeコードポイントを常にサポートするようになりました。ナロービルドとワイドビルドの区別はなくなり、Pythonは、Windowsでもワイドビルドのように動作するようになりました。
  • ナロービルドの廃止に伴い、ナロービルドに固有の問題も修正されました。例:
    • len()は、非BMP文字に対して常に1を返すようになったため、len('\U0010FFFF') == 1;
    • サロゲートペアは文字列リテラルで再結合されないため、'\uDBFF\uDFFF' != '\U0010FFFF';
    • 非BMP文字のインデックス作成またはスライスは期待値を返すため、'\U0010FFFF'[0]'\U0010FFFF'ではなく'\uDBFF'を返すようになりました。
    • 標準ライブラリの他のすべての関数は、非BMPコードポイントを正しく処理するようになりました。
  • sys.maxunicodeの値は常に1114111(16進数で0x10FFFF)になりました。 PyUnicode_GetMax()関数は、下位互換性のために0xFFFFまたは0x10FFFFのいずれかを返します。これは、新しいUnicode APIでは使用しないでください( issue 13054 を参照)。
  • The ./configureフラグ--with-wide-unicodeは削除されました。

Python Regexesの未来

標準のPythonディストリビューションのreライブラリで現在利用可能なものとは対照的に、 MatthewBarnettのregexモジュールの両方Python 2およびPython 3同様 は、ほぼすべての可能な方法ではるかに優れており、最終的にはreに置き換わる可能性があります。あなたの質問との特定の関連性彼のregexライブラリははるかにᴘᴄʀᴇ(iePerl互換性がはるかに高い -))reよりもあらゆる点で、Perl正規表現のPythonへの移植が容易になります。これはゼロからの書き換えであるため(from-のように)スクラッチ、ハンバーガーのようではありません:)、それは非ASCIIを念頭に置いて書かれましたが、reはそうではありませんでした。

したがって、regexライブラリは、物事へのアプローチ方法において、 TS#18:Unicode正規表現 の(現在の)推奨事項にはるかに厳密に従います。それはUTS#18レベル1の要件を満たしているか超えていますが、すべてではないにしても、通常はICU正規表現ライブラリまたはPerl自体—または特に勇気がある場合は、新しいJava 7が正規表現に更新されます。これは レベル1の要件 にも準拠しています。 = UTS#18から。

これらのレベル1の要件を満たすだけでなく、基本的なUnicodeサポートには絶対に不可欠ですが、Pythonの現在のreライブラリでは満たされていません素晴らしいregexライブラリは、 RL2.5 名前付き文字(\N{...}))、 RL2.2 拡張書記素クラスター(\X)、のレベル2要件も満たしています。 TS#18のリビジョン14 からの完全なプロパティに関する新しいRL2.7。

MatthewのregexモジュールはUnicodeの大文字と小文字を区別しない一致がUnicodeで確実に機能するように、Unicodeの大文字と小文字の区別も行いますreは機能しません。

regexがPerlやRubyのような完全なUnicodeケースフォールディングをサポートするようになったため、以下は正しくなくなりました。

非常に小さな違いの1つは、今のところ、Perlの大文字と小文字を区別しないパターンでは完全な文字列指向の大文字と小文字が区別され、regexモジュールでは単純な単一文字指向の大文字と小文字が区別されることですが、これは彼が調査していることです。これは実際には非常に難しい問題であり、Perlを除けば、Rubyさえも試みるだけです。

完全な大文字と小文字を区別しない一致が選択されている場合、これは(たとえば)"ß""SS""ss""ſſ""ſs"(など)に正しく一致することを意味します。 (これは、ギリシャ文字ではラテン文字よりも明らかに重要です。)

スライドまたはドキュメントのソースコードも参照してください 私の3回目のOSCON2011トーク タイトルUnicode Support Shootout:The Good、the Bad、and the (ほとんど)JavaScript、PHP、Go、Ruby、Python、Java、およびPerlでのUnicodeサポートの一般的な問題については醜い "。 Perl正規表現またはおそらくICU正規表現ライブラリ(名前付きキャプチャがない!))を使用できない場合は、Matthewのregex for Pythonはおそらくあなたのベストショットです。


NᴏᴛᴀBᴇɴᴇs.ᴠ.ᴘ。 (= s’ilvousplaît、etmêmes’il nevousplaîtpas :)次の一方的な非営利の非広告は、Python regexライブラリの作成者によって実際にここに置かれたnotではありません。:)

クールなregex機能

Python regexライブラリには超ニート機能のcornucopeiaがあり、そのうちのいくつかは他の正規表現システムはどこにでもあります。これらは、そのᴘᴄʀᴇ-nessまたはその優れたUnicodeサポートのためにそれを使用しているかどうかに関係なくチェックする価値があります。

このモジュールの優れた機能のいくつかは次のとおりです。

  • Variable-width lookbehind、これは正規表現エンジンでは非常にまれな機能であり、本当に必要なときに持っていないのは非常にイライラします。これは、正規表現で最も頻繁に要求される機能である可能性があります。
  • 後方検索なので、最初に自分で文字列を逆にする必要はありません。
  • スコープ付きのismx- typeオプション。これにより、(?i:foo)はfooに対してのみ大文字と小文字が区別され、全体としては折りたたまれません。または(?-i:foo)はfoo上でのみオフになります。これがPerlの仕組みです(またはできます)。
  • 編集距離に基づくあいまいマッチング(UdiManberのagrepglimpseにもあります)
  • \L<list>補間による暗黙の最短から最長のソート済み名前付きリスト
  • どちらかの側ではなく、単語の最初または最後のみに特に一致するメタ文字(\m\M
  • すべてのUnicode行区切り文字のサポート(Javaはこれを行うことができます。Perlは RL1.6 ごとに\Rをやや不愉快に思っていますが。
  • RL1. ごとの括弧で囲まれた文字クラスに対するフルセット操作(和集合、共通部分、差分、対称差)。これは、Perlで取得するよりもはるかに簡単です。
  • (\w+\s+)+のような繰り返しキャプチャグループを許可します。ここでは、最後の一致だけでなく、最初のグループのすべての個別の一致を取得できます。 (C#もこれを行う可能性があると思います。)
  • 先読みで卑劣なキャプチャグループよりも、重複する一致を取得するためのより簡単な方法。
  • Perlの@+および@-配列と同様に、後のスライス/部分文字列操作のためのすべてのグループの開始位置と終了位置。
  • (?|...|...|...|)を介したブランチリセット演算子。Perlで機能する方法で各ブランチのグループ番号をリセットします。
  • 朝にコーヒーを待つように設定できます。
  • RL2. からのより洗練されたWord境界のサポート。
  • デフォルトでUnicode文字列を想定し、 RL1.2a を完全にサポートしているため、\w\b\sなどがUnicodeで機能します。
  • 書記素の\Xをサポートします。
  • \G継続ポイントアサーションをサポートします。
  • 64ビットビルドで正しく機能します(reには32ビットのインデックスしかありません)。
  • マルチスレッドをサポートします。

わかりました、それは十分な誇大宣伝です。 :)

さらに別の優れた代替正規表現エンジン

あなたが正規表現オタクである場合に検討する価値のある最後の選択肢の1つは、 Pythonライブラリバインディング からRuss Coxの素晴らしい RE2ライブラリ です。また、単純な文字ベースの大文字小文字の区別を含め、Unicodeをネイティブにサポートし、reとは異なり、Unicodeの一般カテゴリとUnicodeスクリプトの文字プロパティの両方を提供します。 Unicode処理の種類。

RE2は、ICU、Perl、Pythonで見られる\N{...}名前付き文字サポートなどのいくつかのUnicode機能を見逃していますが、非常に深刻な計算上の利点があり、正規表現エンジンを選択しますWebクエリなどの正規表現を介した飢餓ベースのサービス拒否攻撃が懸念される場合はいつでも。これは、正規表現が定期的に停止し、時間と空間で超指数関数的な爆発が発生するリスクを引き起こす逆参照を禁止することでこれを管理します。

RE2のライブラリバインディングは、C/C++とPythonだけでなく、Perl、特にGoでも利用できます。Goでは、標準の正規表現ライブラリがまもなく置き換えられる予定です。

64
tchrist

'(\w/[^/]+/\w*)'を探しています。

そのように使用され、

import re
x = re.compile('(\w/[^/]+/\w*)')
s = 'match mysql m/^.\0\0\0\n(4\.[-.\w]+)\0...\0/s p/MySQL/ i/$1/'
y = x.findall(s)
# y = ['m/^.\x00\x00\x00\n(4\\.[-.\\w]+)\x00...\x00/s', 'p/MySQL/', 'i/$1/']

Edi Weitzの Regex Coach で遊んでいるときに見つけたので、質問へのコメントのおかげで、その存在を思い出しました。

4
Roshan Mathews

PCRE正規表現を実行する必要があり、Pythonのreモジュールが元のPCREの起源から分岐しているため、 ArkadiuszWahligのPython PCREのバインディング )も確認することをお勧めします。そうすれば、ネイティブPCREにアクセスでき、正規表現フレーバー間で変換する必要がなくなります。

2
David