web-dev-qa-db-ja.com

引用符で区切られた文字列を正規表現と一致させるにはどうすればよいですか?

引用符で区切られた文字列を正規表現と一致させようとしている場合、次のいずれかが「より良い」(「より良い」とは、より効率的で、予期しないことをする可能性が低いことを意味します):

/"[^"]+"/ # match quote, then everything that's not a quote, then a quote

または

/".+?"/   # match quote, then *anything* (non-greedy), then a quote

この質問では、空の文字列(つまり "")は問題ではないと仮定します。私には(正規表現初心者はいないが、確かに専門家はいない)これらは同等であると思われる。

更新:反映後、+文字から*はとにかく空の文字列を正しく処理します。

30
Graeme Perrow

ナンバー2は悪い習慣なので、ナンバー1を使用する必要があります。あなたの後に来る開発者が感嘆符が続く文字列と一致させたいと考えていることを考慮してください。彼は使用する必要があります:

"[^"]*"!

または:

".*?"!

件名がある場合、違いが表示されます。

"one" "two"!

最初の正規表現が一致します:

"two"!

一方、2番目の正規表現は一致します:

"one" "two"!

常にできる限り具体的にしてください。可能な場合は、否定文字クラスを使用してください。

もう1つの違いは、[^ "] *は複数行にまたがることができますが、。*は単一行モードを使用しない限りそうではないことです。[^"\n] *は改行も除外します。

バックトラックに関しては、2番目の正規表現は、一致するすべての文字列のすべての文字をバックトラックします。閉じ引用符が欠落している場合、両方の正規表現はファイル全体をバックトラックします。バックトラックする順序のみが異なります。したがって、理論的には、最初の正規表現の方が高速です。実際には、違いに気付くことはありません。

38
Jan Goyvaerts

より複雑ですが、エスケープされた引用符とエスケープされたバックスラッシュも処理します(エスケープされたバックスラッシュとそれに続く引用符は問題ではありません)

/(["'])((\\{2})*|(.*?[^\\](\\{2})*))\1/

例:
"hello \" world "一致" hello\"world"
"hello \\" world "一致" hello \\ "

14
nico

私はお勧めします:

([\"'])(?:\\\1|.)*?\1

しかし、それはエスケープされた引用文字を処理し、 'と "の両方を引用文字にすることができるからです。

http://blog.stevenlevithan.com/archives/match-quoted-string

ただし、深刻なパフォーマンスの問題がある場合、または引用符が埋め込まれていることを確認できない場合を除き、よりシンプルで読みやすいものを使用してください。

/".*?"/

貪欲でないパターンは、基本的なUnixスタイルの「ed」正規表現ではないことを認めなければなりませんが、かなり一般的になっています。 (?:stuff)のような演算子のグループ化にはまだ慣れていません。

10
Harold Bamford

終端の" 不足している。最初のものは、潜在的に高価な操作である文字列をバックトラックします。 Perl 5.10を使用している場合の代替正規表現は/"[^"]++"/。バージョン1と同じ意味を伝えますが、バージョン2と同じくらい高速です。

5
Leon Timmermans

読みやすいので、2番目に行きます。しかし、私はまだ空の文字列を一致させたいので、私は使用します:

/".*?"/
4
PEZ

パフォーマンスの観点(非常に重い、長い文字列での長時間実行ループ)からは、

"[^"]*"

より速い

".*?"

後者は、各ステップで追加のチェックを行うため、次の文字を覗くからです。前者は、ひたすらひもを転がすことができます。

先ほど言ったように、現実のシナリオでは、これはほとんど目立たないでしょう。したがって、読みやすくなっているので、2つ目を使用します(現在の正規表現フレーバーがサポートしている場合)。それ以外の場合はもちろん、一番です。

2
Tomalak

否定文字クラスを使用すると、入力のどこかに境界文字(例では二重引用符)が存在する場合に一致が防止されます。

あなたの例#1:

/"[^"]+"/ # match quote, then everything that's not a quote, then a quote

一致した引用符の最小のペアのみに一致します-優れており、ほとんどの場合、必要なのはこれだけです。ただし、引用符がネストされており、一致する引用符の最大のペア(または一致するすべての引用符)に関心がある場合は、はるかに複雑な状況にあります。

幸いなことに、Damian Conwayは救助の準備ができています: Text :: Balanced は、一致する引用符が複数ある場合に役立ちます。また、他の句読点のペアと一致するという長所もあります。括弧。

1
Trochee

私は最初の正規表現を好みますが、それは確かに好みの問題です。

最初の方が効率的ですか?

Search for double-quote
add double-quote to group
for each char:
    if double-quote:
        break
    add to group
add double-quote to group

バックトラッキングを含むもう少し複雑なものに対して?

0
Douglas Leeder

「*?」についてさえ知らなかったことを考えると今日まで、そして私は20年以上正規表現を使用してきましたが、最初のものに賛成票を投じました。それは確かにあなたがやろうとしていることを明確にします-あなたは引用符を含まない文字列と一致しようとしています。

0
Paul Tomblin