2

Python で正規表現を使用して複数のキーと値の行を分割しようとしています。私が作業しているファイルには 120 万行を超える行があるため、気にする必要があるすべての異なるキー値の出現に適した数行の別のファイルを作成しました。

@=""
@="0"
@="="
@="@"
@="k=\"v\""
@=dword:00000000
@=hex:00
"k"=""
"k"="="
"k"="@"
"k"="k=\"v\""
"k"="v"
"k"=dword:00000000
"k"=hex:00
"k=\"v\""=""
"k=\"v\""="="
"k=\"v\""="@"
"k=\"v\""="k=\"v\""
"k=\"v\""="v"
"k=\"v\""=dword:00000000
"k=\"v\""=hex:00

私はすでに魅力のように機能するかなり単純な後読み/先読み正規表現で仕事をしています:

#!/usr/bin/env python
import re
regex = re.compile(r'(?<=@|")=(?=[dh"])')

for line in open('split-test'):
    line = line.strip()
    key, value = regex.split(line, 1)

    if key != '@':
        key = key[1:-1]

print '{} => {}'.format(key, value)

出力:

@ => ""
@ => "0"
@ => "="
@ => "@"
@ => "k=\"v\""
@ => dword:00000000
@ => hex:00
k => ""
k => "="
k => "@"
k => "k=\"v\""
k => "v"
k => dword:00000000
k => hex:00
k=\"v\" => ""
k=\"v\" => "="
k=\"v\" => "@"
k=\"v\" => "k=\"v\""
k=\"v\" => "v"
k=\"v\" => dword:00000000
k=\"v\" => hex:00

ご覧のとおり、コード フローでは、キー部分から先頭と末尾の引用符を削除する必要があります。とはいえ、何も最適化しようとしているわけではなく、正規表現自体で同じ結果を達成する方法を学ぼうとしているだけです。

上記の元のコードで多くの変更を試みましたが、次のコードを使用して、恐ろしく遅いが機能する新しい正規表現を正常に取得しました。

#!/usr/bin/env python
import re
regex = re.compile(r'(?:(@)|(?:"((?:(?:[^"\\]+)|\\.)*)"))=')

for line in open('split-test'):
    line = line.strip()
    key, value = filter(None, regex.split(line))

    print '{} => {}'.format(key, value)

ここでは、filter()いくつかの空の文字列に一致するため、使用する必要があります。私は正規表現のマスターではないので、この仕事をするより良い正規表現が書かれていないかと思っています。

4

3 に答える 3

1

引用符を解決しようとする最後の正規表現で正しい軌道に乗っていると思います。これは、分割の代わりにキャプチャ バッファを使用します。

行くには2つの方法があります。

見積もりが不完全(不均衡)であると仮定する -

 #  ^((?:"[^"\\]*(?:\\.[^"\\]*)*"|.)*)=((?:"[^"\\]*(?:\\.[^"\\]*)*"|[^=])*)$

 ^
 (                         # (1 start)
      (?:
           "
           [^"\\]* 
           (?: \\ . [^"\\]* )*
           "
        |  .
      )*
 )                         # (1 end)
 =
 (                         # (2 start)
      (?:
           "
           [^"\\]* 
           (?: \\ . [^"\\]* )*
           "
        |  [^=]
      )*
 )                         # (2 end)
 $

または、それらが完璧であると仮定します-

 #  ^((?:"[^"\\]*(?:\\.[^"\\]*)*"|[^"])*)=((?:"[^"\\]*(?:\\.[^"\\]*)*"|[^="])*)$

 ^
 (                         # (1 start)
      (?:
           "
           [^"\\]* 
           (?: \\ . [^"\\]* )*
           "
        |  [^"]
      )*
 )                         # (1 end)
 =
 (                         # (2 start)
      (?:
           "
           [^"\\]* 
           (?: \\ . [^"\\]* )*
           "
        |  [^="]
      )*
 )                         # (2 end)
 $
于 2013-08-29T17:22:47.490 に答える
1

マッチングの過程で引用符を削り取る正規表現が必要ですか? これをチェックしてください:

r'^(")?((?(1)[^"\\]*(?:\\.[^"\\]*)*|@))"?=([dh"].+$)'

最初の文字が引用符である場合、それはグループ #1 に取り込まれ、(1)条件が成功し、条件分岐の YES 分岐が次のエスケープされていない引用符まですべてを消費します (ただし、引用符自体は消費しません)。そうでない場合、NO 分岐は一致を試み@ます。いずれにせよ、キーは引用符で囲まずにグループ #2 に取り込まれます。

残りの正規表現は簡単です。末尾の引用符 (ある場合) と を消費し=、残りの文字列はグループ #3 に取り込まれます。@"またはで始まる不正な形式の入力と一致する可能性があることに注意してください""。それが受け入れられない場合は、実際の照合が開始される前に、先読みを追加して形式を検証できます。余分な混乱がコアテクニックの説明の邪魔になるので、私は気にしませんでした.

^
(")?
(
  (?(1)
    [^"\\]*(?:\\.[^"\\]*)*
    |
    @
  )
)
"?
=
([dh"].+$)
于 2013-08-29T21:13:48.483 に答える