0

一重引用符または二重引用符で始まり、終わる文字列を検索する RegEx を作成したいと考えています。

たとえば、次のようなケースに一致させることができます。

String: "Hello World"
RegEx: /[\"\'][^\"\']+[\"\']/

ただし、次のように文字列自体に引用符が表示されると問題が発生します。

String: "Hello" World"

上記の式が機能しないことはわかっています。

私ができるようにしたいのは、とにかく必要な機能になるため、文字列自体にエスケープを含めることです。

String: "Hello\" World"

これで、グループ内のさまざまなパターンを持つ長くて複雑な式を思いつくことができました。そのうちの 1 つが次のとおりです。

RegEx: /[\"\'][^\"\']+(\\\"|\\\')+[^\"\']+[\"\']/

しかし、それは私には過剰に思えます。より短く、よりエレガントな解決策があると思います。

意図した構文:

run arg1 "arg1" "arg3 with \"" "\"arg4" "arg\"\"5"

ご覧のとおり、引用符は実際には、スペースを含む文字列が 1 つの文字列としてカウントされるようにするためにのみ使用されます。心配しないでくださいarg1。引用符で囲まれていない引数を照合できるはずです。

これを簡単にします。引数は二重引用符を使用してのみ引用できます。したがって、この質問の要件から一重引用符を削除しました。

私はRui Jarimbaの例を修正しました:

/(?<=")(\\")*([^"]+((\\(\"))*[^"])+)((\\"")|")/

これでほとんどのケースがうまく説明できるようになりましたが、これを無効にできる最後のケースが 1 つあります。

run -a "arg3 \" p2" "\"sa\"mple\"\\"

2 番目の引数 endは、この場合、ネストされた文字列の末尾にバックスラッシュを許可する従来の方法ですが、残念ながら正規表現は、パターンがパターンの末尾にまだ存在する\\"ため、これをエスケープされた引用符と見なします。\"

4

2 に答える 2

4

まず、'文字列を使用して正規表現を記述してください。これで逃げる手間が省けます。

すると、2 つの可能性が見えてきます。あなたの試みの問題は、文字列内の 1 か所で連続してエスケープされた引用符しか許可されないことです。また、これにより、最初と最後で異なる引用符を使用できます。それを回避するには、後方参照を使用できます。したがって、これは a) 少しエレガントで、b) 正しいでしょう:

$pattern = '/(["\'])(\\"|\\\'|[^"\'])+\1/';

交互の順序が重要であることに注意してください。

これの問題は、文字列を区切るために使用しない引用符をエスケープしたくないということです。したがって、もう 1 つの可能性はルックアラウンドを使用することです (後方参照は文字クラス内では使用できないため)。

$pattern = '/(["\'])(?:(?!\1).|(?<=\\\\)\1)+\1/';

単一のリテラル バックスラッシュに一致させるには、常に 4 つの連続するバックスラッシュが必要であることに注意してください。これは、実際の文字列$patternでは最終的に次のよう\\になり、正規表現エンジンが最初のものを「使用」して2番目のものをエスケープするためです。

これは、開始引用符でない場合、任意の文字に一致します。または、前の文字がバックスラッシュの場合、開始引用符と一致します。

動作デモ。

ちなみに、これは次と同等です。

$pattern = '/(["\'])(?:\\\\\1|(?!\1).)+\1/';

しかし、ここでもこの順番で交代を書かなければなりません。

動作デモ。

最後に 1 つ。可能な 2 つの文字列 (一重引用符と二重引用符で囲まれた文字列) を別々に指定することで、後方参照を回避できます。

$pattern = '/"(?:\\\\"|[^"])+"|\'(?:\\\\\'|[^\'])+\'/';

しかし、あなたは短くてエレガントなものを探していると言っていました;) (ただし、この最後のものはより効率的かもしれません...しかし、それをプロファイルする必要があります)。

私のすべての正規表現では、1 つのケースが考慮されていないことに注意してください。つまりHello \" World "Hello" World、あなたを与えるでしょう" World"。これは、別の否定的な後読みを使用して回避できます (例として、動作するデモを提供した 2 番目の正規表現を使用します。他のすべての正規表現でも同じように動作します)。

$pattern = '/(?<!\\\\)(["\'])(?:\\\\\1|(?!\1).)+\1/';
于 2012-11-21T12:15:05.573 に答える
1

この正規表現を試してください:

['"]([^'"]+((\\(\"|'))*[^'"])+)['"]

次の文字列を指定します。

"Hello" World 'match 2' "wqwqwqwq wwqwqqwqw" no match here oopop "Hello \" World"

一致します

"Hello"
'match 2'
"wqwqwqwq wwqwqqwqw"
"Hello \" World"
于 2012-11-21T12:17:21.630 に答える