引用符をエスケープする引用符付き文字列の正規表現


120

" It's big \"problem "正規表現を使用して部分文字列を取得するにはどうすればよいですか?

s = ' function(){  return " It\'s big \"problem  ";  }';     

1
「Is」のみを含む文字列で「It's」をどのように見つけますか?私はあなたのためにそれを修正しますが、あなたが使用している言語に適用される単一引用符/エスケープ規則がわかりません。
ジョナサンレフラー、


2
実際、日付を見ると、もう1つの質問がこの質問の重複であることがわかります。いずれにせよ、必ず私の答えを確認しください。
ridgerunner

@ridgerunner:あなたが提案したとおり、これを閉じることに投票します。それは本当の他の質問がより新しいですが、それはまたはるかに良いです(主にあなたの答えに感謝します)。
アランムーア

回答:


158
/"(?:[^"\\]|\\.)*"/

RegexコーチとPCREワークベンチで動作します。

JavaScriptでのテストの例:

    var s = ' function(){ return " Is big \\"problem\\", \\no? "; }';
    var m = s.match(/"(?:[^"\\]|\\.)*"/);
    if (m != null)
        alert(m);


23
理にかなっています。プレーンな英語:「引用符またはバックスラッシュではない任意の文字」または「バックスラッシュの後に任意の文字が続く」の0個以上を囲む2つの引用符。私はそうするつもりがなかったなんて信じられない...
Ajedi32

7
自分で答えます。=)(?:...)は、パッシブグループまたは非キャプチャグループです。これは、後で後方参照できないことを意味します。
magras

たくさん検索してたくさんテストした後、これが私がこの一般的な問題に対して見つけた真の唯一の解決策です。ありがとう!
Cancerbero 2015年

9
これをありがとう。私は、単一引用符と一致したかっただけでなくので、私はこれにそれを適応させることになった:/(["'])(?:[^\1\\]|\\.)*?\1/
レオ

を使用するとvar s = ' my \\"new\\" string and \"this should be matched\"';、このアプローチは予期しない結果につながります。
WiktorStribiżew2016

32

これは、多くのLinuxディストリビューションで利用可能なnanorc.sampleからのものです。Cスタイル文字列の構文強調表示に使用されます

\"(\\.|[^\"])*\"

を使用するとvar s = ' my \\"new\\" string and \"this should be matched\"';、このアプローチは予期しない結果につながります。
WiktorStribiżew2016

1
私が行った最初の場所はc.nanorcでした。このようなすべてをダブルエスケープするまで、C文字列リテラルの一部として機能させることができませんでした" \"(\\\\.|[^\\\"])*\" "
hellork

これは、libcのegrepおよびre_comp / re_exec関数で機能します。
fk0

19

ePharaohが提供するように、答えは

/"([^"\\]*(\\.[^"\\]*)*)"/

上記を一重引用符または二重引用符で囲まれた文字列に適用するには、次を使用します。

/"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/

2
これは、99のエスケープを含む単一の1.5 KBの引用符付きの文字列で私のために機能した唯一のセットです。このページの他のすべての式は、テキストエディターでオーバーフローエラーが発生しました。ここでのほとんどはブラウザで動作しますが、覚えておくべきことだけです。フィドル:jsfiddle.net/aow20y0L
Beejor

3
説明については、以下の@MarcAndrePoulinの回答を参照してください。
2015

10

ここで提供されるソリューションのほとんどは、代替の繰り返しパス、つまり(A | B)*を使用します。

一部のパターンコンパイラは再帰を使用してこれを実装しているため、大きな入力でスタックオーバーフローが発生する可能性があります。

たとえばJava:http : //bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993

このようなもの: "(?:[^"\\]*(?:\\.)?)*"、またはGuy Bedfordによって提供されるものは、ほとんどのスタックオーバーフローを回避する解析ステップの量を削減します。


9
"(?:\\"|.)*?"

エスケープされた引用符\"との.パスを交互に使用すると、遅延量指定子*?によって、引用符で囲まれた文字列の末尾を超えないようになります。.NET Framework REクラスで動作します


しかし失敗します"\\"
Ian


/"(?:(?:\\"|[^"])*)"/gこれは修正されるはずです
デイブ、

7
/"(?:[^"\\]++|\\.)*+"/

man perlrePerl 5.22.0がインストールされたLinuxシステムから直接取得。最適化として、この正規表現は、両方の「所有代名詞」フォームを使用+し、*閉鎖引用符なしの文字列はどのような場合に一致しないことが予め分かっているため、バックトラッキングを防止します。


4
/(["\']).*?(?<!\\)(\\\\)*\1/is

引用符で囲まれた文字列で動作するはずです


1
ニースですが、要求に対して柔軟性が高すぎます(単一引用符と一致します...)。そして、何かを見落とさない限り、/ "。*?(?<!\)" /に簡略化できます。ああ、一部の言語(JavaScriptなど)は、否定的な後読み式を理解できません。
PhiLho 2008年

1
@PhiLho、単一(?<!\\)だけを使用すると、文字列の末尾のエスケープされたバックスラッシュで失敗します。ただし、JavaScriptの後読みについてはそうです。
Markus Jarderot、2008年

4

これはPCREで完璧に動作し、StackOverflowに該当しません。

"(.*?[^\\])??((\\\\)+)?+"

説明:

  1. 引用符で囲まれた文字列はすべてChar:で始まり"ます。
  2. 任意の数の任意の文字を含めることができます。.*?{レイジーマッチ}; 非エスケープ文字で終わる[^\\];
  3. ステートメント(2)は、文字列が空( "")になる可能性があるため、Lazy(!)はオプションです。そう:(.*?[^\\])??
  4. 最後に、引用符で囲まれた文字列はすべてChar(")で終わりますが、その前に偶数個のエスケープ記号ペアを付けることができます(\\\\)+。そしてそれはGreedy(!)オプションです:((\\\\)+)?+{Greedy matching}、文字列が空であるか、またはペアを終了しないためです!

これは世界で最も効率的なパターンではありませんが、そのアイデアは興味深いものです。:あなたはこのようにそれを短縮できることに注意してください"(.*?[^\\])?(\\\\)*"
カシミールらイポリット

2

ここに "と"の両方で機能するものがあり、最初に他の人を簡単に追加できます。

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

最初のグループ( "または ')にあるものと完全に一致する後方参照(\ 1)を使用します。

http://www.regular-expressions.info/backref.html


これは非常に優れた解決策ですが、逆参照のようなものがないため、[^\1]置き換える必要が.あります。最初の条件は、何か問題が発生する前に常に一致します。
Seph Reed 2017

@SephReed –に置き換える[^\1]と、.この正規表現が事実上に変更さ("|').*?\1れ、で一致"foo\""foo \" bar"ます。とはいえ[^\1]、実際に仕事をするのは難しいです。@ mathiashansen -あなたは扱いにくく、高価で、より良いオフにしている(?!\1).(全体の正規表現ので、いくつかの効率のクリーンアップで、でしょう(["'])(?:\\.|(?!\1).)*+\1+あなたのエンジンがそれをサポートしていない場合は省略可能です。
アダム・カッツ

2

これまで触れられたことがないオプションは次のとおりです。

  1. 文字列を逆にします。
  2. 逆の文字列に対してマッチングを実行します。
  3. 一致した文字列を元に戻します。

これには、エスケープされたオープンタグを正しく照合できるという追加のボーナスがあります。

次の文字列があったとしましょう。String \"this "should" NOT match\" and "this \"should\" match" ここで\"this "should" NOT match\"は、一致して"should"はならず、一致する必要があります。その上でthis \"should\" match一致する必要があり、一致してはなり\"should\"ません。

最初の例。

// The input string.
const myString = 'String \\"this "should" NOT match\\" and "this \\"should\\" match"';

// The RegExp.
const regExp = new RegExp(
    // Match close
    '([\'"])(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))' +
    '((?:' +
        // Match escaped close quote
        '(?:\\1(?=(?:[\\\\]{2})*[\\\\](?![\\\\])))|' +
        // Match everything thats not the close quote
        '(?:(?!\\1).)' +
    '){0,})' +
    // Match open
    '(\\1)(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))',
    'g'
);

// Reverse the matched strings.
matches = myString
    // Reverse the string.
    .split('').reverse().join('')
    // '"hctam "\dluohs"\ siht" dna "\hctam TON "dluohs" siht"\ gnirtS'

    // Match the quoted
    .match(regExp)
    // ['"hctam "\dluohs"\ siht"', '"dluohs"']

    // Reverse the matches
    .map(x => x.split('').reverse().join(''))
    // ['"this \"should\" match"', '"should"']

    // Re order the matches
    .reverse();
    // ['"should"', '"this \"should\" match"']

では、RegExpについて説明しましょう。これは、正規表現を簡単に3つの部分に分割できることです。次のように:

# Part 1
(['"])         # Match a closing quotation mark " or '
(?!            # As long as it's not followed by
  (?:[\\]{2})* # A pair of escape characters
  [\\]         # and a single escape
  (?![\\])     # As long as that's not followed by an escape
)
# Part 2
((?:          # Match inside the quotes
(?:           # Match option 1:
  \1          # Match the closing quote
  (?=         # As long as it's followed by
    (?:\\\\)* # A pair of escape characters
    \\        # 
    (?![\\])  # As long as that's not followed by an escape
  )           # and a single escape
)|            # OR
(?:           # Match option 2:
  (?!\1).     # Any character that isn't the closing quote
)
)*)           # Match the group 0 or more times
# Part 3
(\1)           # Match an open quotation mark that is the same as the closing one
(?!            # As long as it's not followed by
  (?:[\\]{2})* # A pair of escape characters
  [\\]         # and a single escape
  (?![\\])     # As long as that's not followed by an escape
)

これはおそらく画像形式ではるかに明確です:JexのRegulexを使用して生成

githubの画像(JavaScript正規表現ビジュアライザー) 申し訳ありませんが、画像を含めるのに十分な評判がないため、現時点ではリンクにすぎません。

この概念を使用した関数の例の要点を次に示します。https//gist.github.com/scagood/bd99371c072d49a4fee29d193252f5fc#file-matchquotes-js


0

正規表現はすべてのstring-yの特効薬ではないことを覚えておく必要があります。いくつかのものは、カーソルを使って行う方が簡単で、リニアで手動のシークです。A CFLはかなり自明トリックを行うだろうが、多くのCFLの実装(私の知る限りでは)ありません。


3
確かにそうですが、この問題は正規表現の機能の範囲内であり、それらの実装は非常にたくさんあります。
アランムーア




0

一部のファイルの解析を妨げる可能性がある引用符付きの文字列を削除しようとすると、同様の問題に直面しました。

私はあなたが思いつくことができるどんな複雑な正規表現にも勝る2ステップの解決策に終わりました:

 line = line.replace("\\\"","\'"); // Replace escaped quotes with something easier to handle
 line = line.replaceAll("\"([^\"]*)\"","\"x\""); // Simple is beautiful

読みやすく、おそらくより効率的です。


0

IDEがIntelliJ Ideaの場合、これらすべての頭痛の種を忘れて、正規表現を文字列変数に格納でき、それを二重引用符の中にコピーアンドペーストすると、自動的に正規表現の受け入れ可能な形式に変わります。

Javaの例:

String s = "\"en_usa\":[^\\,\\}]+";

これで、この変数を正規表現またはどこでも使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.