RegEx:引用符の間の値の取得


回答:


361

私は以下を使用して大きな成功を収めています:

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

ネストされた引用符もサポートしています。

これがどのように機能するかについてより深い説明が必要な人のために、ユーザーephemientからの説明があります:

([""'])引用と一致; ((?=(\\?))\2.)バックスラッシュが存在する場合は、それをぐちゃぐちゃにし、それが発生するかどうかに関係なく、文字に一致させます。*?何度も一致します(貪欲ではなく、終了の引用を食べません)。\1オープニングに使用されたのと同じ見積もりと一致します。


6
@steve:これも不正確に一致し"foo\"ます。先読みのトリックにより、?量指定子が所有権を持つようになります(正規表現フレーバーが?+構文またはアトミックグループ化をサポートしていない場合でも)
Robin

1
Pythonでは、これによりエラーが発生します。sre_constants.error:オープングループを参照できません
a1an

9
これは、一致する引用符を含む値を返します。それが要求されたように、引用符の間にあるコンテンツのみを返す機会はありませんか?
Martin Schneider

4
先読みを所有的量指定子として乱用することは完全に不要であり、混乱を招きます。ただ、交代を使用:(["'])(?:\\.|[^\\])*?\1
アラン・フェイ

2
空の文字列を回避する方法?
Vikas Bansal

333

一般的に、次の正規表現の断片はあなたが探しているものです:

"(.*?)"

これは貪欲ではない*?次の二重引用符を除くすべてをキャプチャする演算子。次に、言語固有のメカニズムを使用して、一致したテキストを抽出します。

Pythonでは、次のことができます。

>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']

11
これはすばらしいことですが、引用符がエスケープされた文字列は処理しません。例"hello \" world"
robbyt 2015

JavaScriptの一致を使用すると、これは引用符にも一致します。これは、ここで説明するように幹部を反復して動作します:stackoverflow.com/questions/7998180/...
Kiechlus

4
@robbyt返答が少し遅いのはわかっていますが、否定的な後読みはどうですか?"(.*?(?<!\\))"
マテウス

4
ありがとう-エスケープされた引用符がないと確信できる場合、これはより簡単です。
squarecandy

一言。驚くばかり !
Shiva Avula

89

私は行きます:

"([^"]*)"

[^「]以外の任意の文字のための正規表現は' "
私は非欲張り多くのオペレータの上にこれを使用する理由は、私は念の私はそれが正しい取得するためにそれを探し続ける必要があるということです。


1
これは、さまざまな正規表現の解釈の間でも適切に動作します。
Phil Bennett、

5
これは私の正気を救いました。.NETのRegEx実装では、 "(。*?)"には望ましい効果はありません(貪欲ではありません)が、 "([^"] *) "にはあります
Jens Neubauer

これがベストアンサーです。ありがとう
Lmao 123

28

エスケープされた引用符を処理する2つの効率的な方法を見てみましょう。これらのパターンは、簡潔でも美的でもないように設計されていますが、効率的です。

これらの方法では、最初の文字の識別を使用して、代替のコストなしで文字列内の引用符をすばやく検索します。(アイデアは、交互の2つのブランチをテストせずに、引用符ではない文字をすばやく破棄することです。)

引用符間のコンテンツは、より効率的になるように(繰り返しの代わりに)展開されたループで記述されます。 [^"\\]*(?:\\.[^"\\]*)*

明らかに引用符のバランスが取れていない文字列を処理する場合は、代わりに所有格指定子を使用する[^"\\]*+(?:\\.[^"\\]*)*+か、過度のバックトラックを防ぐためにそれらをエミュレートする回避策を使用できます。次の(エスケープされていない)引用符または文字列の終わりまで、引用符で囲まれた部分を開始引用符にすることもできます。この場合、所有格指定子を使用する必要はありません。最後の引用符をオプションにするだけで済みます。

注意:引用符はバックスラッシュでエスケープされない場合がありますが、引用符を繰り返すことによりエスケープされます。この場合、コンテンツサブパターンは次のようになります。[^"]*(?:""[^"]*)*

パターンは、キャプチャグループと後方参照(["']).....\1たとえばのようなものの使用を避け、単純な代替を使用しますが["']、最初は重要です。

Perlのような:

["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')

(これ(?s:...)は非キャプチャグループ内のdotall / singlelineモードをオンにする構文上の砂糖です。この構文がサポートされていない場合は、すべてのパターンでこのモードをオンにするか、ドットをで置き換えることができます[\s\S]

(このパターンの記述方法は完全に「手動」であり、最終的なエンジン内部の最適化は考慮されていません)

ECMAスクリプト:

(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')

拡張されたPOSIX:

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

または単に:

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

1
Pythonは、生の文字列形式のECMAスクリプト、つまりr "" "ECMAスクリプト" ""を
受け入れます

1
これはすばらしいです。ECMAを改行して改行をエスケープし、二重引用符でキャリッジリターンを処理するのは非常に簡単でした。
Douglas Gaskell

@ douglasg14b:ありがとう。JavaScriptで使用する場合は、/pattern/エスケープせずにリテラル表記を使用するだけでよいことに注意してください(オブジェクト表記ではなくnew RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");
Casimir et Hippolyte

@ a1an:はい、ただし、shere:を削除して、パターンのどこかに(?s:置くと、Perlバージョンを使用できます(?s)
Casimir et Hippolyte

16

受け入れ答えの正規表現は、そのsourroundingの引用符を含む値を返します"Foo Bar"し、"Another Value"試合など。

引用符囲まれたのみを返すRegExは次のとおりです(質問者が要求したとおり)。

二重引用符のみ(キャプチャグループ#1の値を使用):

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

単一引用符のみ(キャプチャグループ#1の値を使用):

'(.*?[^\\])'

両方(キャプチャグループ#2の値を使用):

(["'])(.*?[^\\])\1

-

エスケープおよびネストされた引用符をすべてサポートします。


なぜこれが機能するのですか?私が使っていたsrc="(.*)"が、最後の『内容」をお使いの正規表現は、しかし、=のみSRCを選択し、』前に明らかにそれはすべてを選択しましたが、私は理解していなかったか?
ルーカスブスタマンテ

Iこの1それの簡略化のために多く、それが空であるかの引用符の間には値が非常にだけでなく、私が発見を処理しないように
RedactedProfile

16

特に、これらの回答はいずれも、返される一致が引用符内のテキストである正規表現を生成しません。MA-Maddenは、マッチ全体ではなく、キャプチャされたグループとして内部一致のみを取得しようとします。実際にそれを行う1つの方法は次のとおりです。

(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)

この例は、このデモhttps://regex101.com/r/Hbj8aP/1で見ることができます

ここで重要なのは、開始時?<=の肯定的な先読み()と終了時の肯定的な先読み(?=)です。後読みは現在の文字の後ろを調べて引用をチェックします。見つかった場合はそこから開始し、先読みは引用の前の文字をチェックし、見つかった場合はその文字で停止します。後読みグループ(["'])は括弧で囲まれて、最初に見つかった引用のグループを作成します。これは最後の先読みで使用され(?=\1)、対応する引用が見つかったときにのみ停止するようにします。

他の唯一の複雑な点は、先読みが実際に終了引用符を消費しないため、同じ行の終了引用符と開始引用符の間のテキストが一致する原因となる開始後読みによって再び検出されることです。冒頭の引用(["']\b)に単語の境界を付けると、これに役立ちますが、先読みを超えて移動したいのですが、可能ではないと思います。途中でエスケープされたキャラクターを許可するビットは、アダムの答えから直接取っています。



8

上記のパターン(["'])(?:(?=(\\?))\2.)*?\1はうまくいきますが、私はそのパフォーマンスを心配しています(悪くはありませんが、もっと良いかもしれません)。その下の鉱山は約20%高速です。

パターン"(.*?)"は不完全です。これを読んでいる皆への私のアドバイスはただそれを使用しないでください!!!

たとえば、以下のような多くの文字列をキャプチャすることはできません(必要に応じて、徹底的なテストケースを提供できます)。

$ string = 'お元気ですか?私は\'「ありがとう、罰金をmは、

それらの残りは上記のものと同じように「良い」です。

パフォーマンスと精度の両方を本当に重視する場合は、次のいずれかから始めます。

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

私のテストでは、出会ったすべての文字列をカバーしましたが、機能しないものが見つかった場合は、喜んで更新します。

オンラインの正規表現テスターでパターンを確認してください


1
私はあなたのパターンの単純さが好きですが、パフォーマンスに関しては、Casimir et Hippolyteのパターンはすべての拡張ソリューションを水から吹き飛ばします。さらに、文の末尾のエスケープされた引用符など、拡張されたエッジケースの問題がパターンにあるようです。
wp78de

7

私は、引用符をエスケープしながら、引用符の間のコンテンツを一致させるEugen Mihailescuのソリューションが好きでした。しかし、エスケープに関するいくつかの問題を発見し、それらを修正するために次の正規表現を思いつきました:

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

それはトリックを行い、それでもかなりシンプルでメンテナンスが簡単です。

デモ(いくつかのテストケースがあります。自由に使用して拡張してください)。


PS:完全一致()の引用符で囲まれたコンテンツ必要$0で、パフォーマンスの低下を恐れない場合:

(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)

残念ながら、アンカーとしての引用符\bがないと、開始引用符の後にスペースや単語以外の境界文字でうまく機能しない境界を追加する必要がありました。

または、単にグループを$2追加して初期バージョンを変更し、文字列形式を抽出します

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

PPS:効率のみを重視する場合は、Casimir et Hippolyteのソリューションを使用してください。それは良いものです。


観測:2番目の正規表現は、-経度座標の場合のように、マイナス記号の付いた値を見逃します。
Crowcoder

何も変えなかった。あなたが問題を観察しないならば、それは多分私が使っている正規表現の味です。私はregex101siteを使用していましたが、phpスタイルの正規表現だと思います。
Crowcoder

これが私が話していることのデモです。経度(-96.74025)と一致すると期待していましたが、一致しません。
Crowcoder

@Crowcoderありがとうございます。はい、これはアンカーとして機能し、一致の重複を回避するのに役立ちますが、入力ではうまく機能しない単語境界が原因です。更新された回答に記載されているように、実際には追加のグループがより良いオプションです。
wp78de

6

このバージョン

  • エスケープされた引用のアカウント
  • バックトラックを制御する

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

これは複数の文字列にまたがり、二重バックスラッシュを正しく処理しないようです。たとえば、文字列: foo 'stri \\ ng 1' bar 'string 2' and 'string 3' Debuggex Demo
miracle2k

文字クラスで後方参照を使用することはできません。
HamZa 2014年

5

もっと回答!これが私が使った解決策です

\"([^\"]*?icon[^\"]*?)\"

TLDR;
単語のアイコンをあなたが言った引用と出来上がりで探しているものに置き換えてください!


これが機能する方法は、キーワードを検索し、引用符の間にある他の何も気にしないことです。EG:
id="fb-icon"
id="icon-close"
id="large-icon-close"
正規表現は引用符を"
探し、次にそれが"
見つかるまで存在icon
しない可能性のある文字のグループを探し、それ以外の可能性のある文字のグループは"
終わりを探します"


1
どうもありがとうございました。この回答の正規表現は/ を(受け入れられた回答とは異なり)2番目のグループとして返すため、name="value"をすべてので置き換えることができました。検索置換name={"value"}iconvalue=\"([^\"]*?[^\"]*?)\" ={"$1"}
パリサンド2017

反対票を説明しますか?状況によってはうまく機能します。
James Harrington

私に返信していますか?
パリサンド2018

@Palisand先日、誰かがこの投稿に投票せず、説明もありませんでした。
James Harrington

これは、引用符で囲まれた特定のテキストを見つける唯一の回答のようです
Top-Master

4

私はAxemanのより拡張されたバージョンが好きでしたが、それに問題がありました(たとえば、一致しませんでした)

foo "string \\ string" bar

または

foo "string1"   bar   "string2"

正しく、私はそれを修正しようとしました:

# opening quote
(["'])
   (
     # repeat (non-greedy, so we don't span multiple strings)
     (?:
       # anything, except not the opening quote, and not 
       # a backslash, which are handled separately.
       (?!\1)[^\\]
       |
       # consume any double backslash (unnecessary?)
       (?:\\\\)*       
       |
       # Allow backslash to escape characters
       \\.
     )*?
   )
# same character as opening quote
\1

3
string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)

これを試してみてください、魅力のように動作します!!!

\ スキップ文字を示します


最初の行が実際のPythonコードである場合は、文字列を作成します" foo bar" "loloo"。正規表現で行ったように、それを生の文字列でラップするつもりだったと思います:r'"\" foo bar\" \"loloo\""'。必要に応じて、SOの優れたフォーマット機能を利用してください。化粧品だけではありません。それらを使用しないと、文字通りあなたは何を言おうとしているのかを知ることができません。そして、Stack Overflowへようこそ!
アランムーア

アランの助言に感謝します。私は実際にこのコミュニティに初めて参加しました。次回は、これらすべてを確実に心がけます...誠に申し訳ございません。
mobman 14

2

アダムの答えとは異なり、私は単純ですがうまくいきました:

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

次のように引用符で囲んでコンテンツを取得する場合は、括弧を追加します。

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

次に、$1引用文字と$2一致し、コンテンツ文字列と一致します。


1
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'

これは次の結果になります:> Foo Bar <> <> but this <

ここでは、わかりやすくするために> <の間に結果文字列を示しました。また、このsedコマンドで貪欲でないバージョンを使用して、最初にその「」の前後でジャンクを最初にスローし、次にこれを「」の間の部分に置き換えますとこれを> <で囲みます。


1

Greg H.から私は自分のニーズに合うようにこの正規表現を作成することができました。

引用符で囲まれて修飾された特定の値に一致させる必要がありました。完全一致でなければなりません。部分一致ではヒットがトリガーされません。

たとえば、「test」は「test2」と一致しませんでした。

reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
    print "winning..."

猟師


1

ドット構文など、特定のサフィックスのみが付いた文字列を検索する場合は、次のように試すことができます。

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

どこ .localized接尾辞は。

例:

print("this is something I need to return".localized + "so is this".localized + "but this is not")

キャプチャ"this is something I need to return".localizedします"so is this".localizedが、キャプチャしません"but this is not"


1

Microsoft VBAコーダーのサブセットに対する補足的な回答は、ライブラリMicrosoft VBScript Regular Expressions 5.5を1つだけ使用し、これは次のコードを提供します

Sub TestRegularExpression()

    Dim oRE As VBScript_RegExp_55.RegExp    '* Tools->References: Microsoft VBScript Regular Expressions 5.5
    Set oRE = New VBScript_RegExp_55.RegExp

    oRE.Pattern = """([^""]*)"""


    oRE.Global = True

    Dim sTest As String
    sTest = """Foo Bar"" ""Another Value"" something else"

    Debug.Assert oRE.test(sTest)

    Dim oMatchCol As VBScript_RegExp_55.MatchCollection
    Set oMatchCol = oRE.Execute(sTest)
    Debug.Assert oMatchCol.Count = 2

    Dim oMatch As Match
    For Each oMatch In oMatchCol
        Debug.Print oMatch.SubMatches(0)

    Next oMatch

End Sub

0

私にとってこれを働いた:

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

私はこのような文で使用しました:

preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);

そしてそれは素晴らしく機能しました。


このアプローチの弱点は、文字列が一重引用符で始まり、二重引用符で終わる場合、またはその逆の場合に一致することです。
Ghopper21

また、「@を忘れないでください」をキャッチするのにも問題があります。「ドン」の後に停止します。
Benny Neugebauer

0

上記のすべての答えは良いです... すべてのユニコード文字をサポートしていないことを除いて!ECMAスクリプト(Javascript)

Nodeユーザーの場合は、すべてのUnicode文字をサポートする承認された回答の修正バージョンが必要になる場合があります。

/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu

こちらをお試しください


1
非ユニコード文字とは何ですか?AFAIK unicodeはすべての文字をカバーます。
トト

1
なぜそれがJavaScriptの質問だと思いますか?さらに、後読みはすべてのブラウザーでサポートされているわけではありません。regex101がスローします? The preceding token is not quantifiable
Toto

@Toto、つまり、「すべてのUnicode文字をサポートしているわけではない」ということです。ありがとうございました。問題は一般的に正規表現に関するものですが、単語境界アサーションを使用するとJavaScriptで望ましくない動作が発生することを強調したくありません。そしてもちろん、JavaScriptは一般にブラウザ向けですが、Nodeもあります。
ドノバンP
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.