JavaScriptで2つの文字列間の文字列を取得する正規表現


166

非常によく似た投稿を見つけましたが、ここでは正規表現をまったく取得できません。

他の2つの文字列の間にある文字列を返す正規表現を記述しようとしています。たとえば、「cow」と「milk」の間にある文字列を取得したいとします。

私の牛はいつも牛乳を出しています

戻るだろう

「常に与える」

ここに私が今までつなぎ合わせた表現があります:

(?=cow).*(?=milk)

ただし、これは文字列「cow always present」を返します。


6
私はこの古い質問に出くわし、testREが配列である理由を明確にしたいと思いました。test.matchは、完全一致として最初のインデックス(したがって、cow(。*)milkと一致する文字列)を持つ配列を返し、次に、(。*)のようにトラップされたすべての文字列に、2番目の括弧のセットがあった場合、その後testRE [2]に参加
Salketer 2013年

4
改行を含む文字列を検索する場合、このソリューションは機能しません。このような場合は、「STRING_ONE([\\ s \\ S] *?)STRING_TWO」を使用する必要があります。stackoverflow.com/questions/22531252/...
Michael.Lumley

あくまでも参考のためのMDNにマッチ方法developer.mozilla.org/en/docs/Web/JavaScript/Reference/...
vzR

回答:


183

先読み(その(?=部分)は入力を消費しません。これはゼロ幅アサーションです(境界チェックと後読みと同様)。

このcow部分を消費するために、ここで定期的に一致させる必要があります。その間の部分をキャプチャするには、キャプチャグループを使用します(キャプチャするパターンの部分をかっこで囲みます)。

cow(.*)milk

先読みはまったく必要ありません。


26
これをテストすると、提供された正規表現には「牛」と「牛乳」の両方が含まれています...
TheCascadian

4
これにはステップがありません。一致の結果が得られたら、でmatched[1]一致したテキスト全体ではなく、で最初のキャプチャグループの一致したテキストを抽出する必要がありますmatched[0]
Rory O'Kane

7
JavaScriptでは、実際には([\s\S]*?)ではなくを使用する必要があります(.*?)
Qian Chen

7
これは便利なテクニックですが、@ TheCascadian
Almir Camposが

@AlmirCampos-私が間違っていない場合、「cow」と「milk」を一致させずにこの一致を行う方法はありません(これらの2つの間にあるものを一致させたいため)。問題はRegEx自体にはありませんが、後でそれをどのように処理するかです(Rory O'Kaneが言及)。それ以外の場合は、周囲のスペースでのみ一致する可能性があります-そして、それはあなたに非常に間違ったリターンを与えるでしょうね?
生まれ

69

JavaScriptで2つの文字列間の文字列を取得する正規表現

大部分のケースで機能する最も完全なソリューションは、遅延ドットマッチングパターンを持つキャプチャグループを使用することです。ただし、JavaScript正規表現のドットは改行文字と一致しないため、100%の場合に機能するのはa または/ / 構成です。.[^][\s\S][\d\D][\w\W]

ECMAScript 2018以降の互換性のあるソリューション

ECMAScript 2018をサポートするJavaScript環境では、s修飾子により.改行文字を含む任意の文字を照合でき、正規表現エンジンは可変長の後読みをサポートします。したがって、次のような正規表現を使用できます

var result = s.match(/(?<=cow\s+).*?(?=\s+milk)/gs); // Returns multiple matches if any
// Or
var result = s.match(/(?<=cow\s*).*?(?=\s*milk)/gs); // Same but whitespaces are optional

どちらの場合も、現在位置はのcow後に1/0以上の空白でチェックされ、cow可能な限り少ない0+文字が照合されて消費され(=照合値に追加)、次にmilk(任意のこの部分文字列の前の1/0以上の空白)。

シナリオ1:単一行入力

これと以下の他のすべてのシナリオは、すべてのJavaScript環境でサポートされています。回答の下部にある使用例を参照してください。

cow (.*?) milk

cowが最初に検出され、次にスペース、次に、改行文字以外の0+文字(*?遅延量指定子の数はできるだけ少ない)がグループ1にキャプチャされ、その後にスペースがmilk続く必要があります(これらも一致して消費されます) )。

シナリオ2:複数行入力

cow ([\s\S]*?) milk

ここでは、cow最初にスペースが照合され、次に、可能な限り少ない0+文字が照合されてグループ1にキャプチャされ、次にスペースmilkが照合されます。

シナリオ3:重複する一致

のような文字列が>>>15 text>>>67 text2>>>あり、>>>+ number+ whitespaceとの間に2つの一致を取得する必要がある>>>場合/>>>\d+\s(.*?)>>>/g、これは使用できません。これは、最初の一致を見つけると>>>以前67はすでに消費されているため、1つの一致しか見つけられないためです。ポジティブ先読みを使用して、実際に「ゴブリング」する(つまり、一致に追加する)ことなく、テキストの存在を確認できます。

/>>>\d+\s(.*?)(?=>>>)/g

参照してくださいオンライン正規表現のデモが生じるtext1text2、グループとして1つの内容が見つかりました。

文字列のすべての可能な一致を取得する方法も参照してください。

パフォーマンスに関する考慮事項

.*?非常に長い入力が与えられると、正規表現パターン内の遅延ドットマッチングパターン()がスクリプトの実行を遅くする可能性があります。多くの場合、アンロールザループテクニックがより役立ちます。との間のすべてを取得しようとするcowmilk"Their\ncow\ngives\nmore\nmilk"で始まらないすべての行に一致する必要があるだけなmilkので、代わりに次のようにcow\n([\s\S]*?)\nmilk使用できます。

/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm

正規表現のデモを参照してください(可能な場合は\r\n、を使用してください/cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm)。この小さなテスト文字列では、パフォーマンスの向上はごくわずかですが、テキストが非常に大きいと、違いが感じられます(特に、行が長く、改行がそれほど多くない場合)。

JavaScriptでの正規表現の使用例:

//Single/First match expected: use no global modifier and access match[1]
console.log("My cow always gives milk".match(/cow (.*?) milk/)[1]);
// Multiple matches: get multiple matches with a global modifier and
// trim the results if length of leading/trailing delimiters is known
var s = "My cow always gives milk, thier cow also gives milk";
console.log(s.match(/cow (.*?) milk/g).map(function(x) {return x.substr(4,x.length-9);}));
//or use RegExp#exec inside a loop to collect all the Group 1 contents
var result = [], m, rx = /cow (.*?) milk/g;
while ((m=rx.exec(s)) !== null) {
  result.push(m[1]);
}
console.log(result);

最新のString#matchAll方法を使用する

const s = "My cow always gives milk, thier cow also gives milk";
const matches = s.matchAll(/cow (.*?) milk/g);
console.log(Array.from(matches, x => x[1]));


51

牛と牛乳の間にあるものを(先頭/末尾のスペースなしで)取得する正規表現を次に示します。

srctext = "My cow always gives milk.";
var re = /(.*cow\s+)(.*)(\s+milk.*)/;
var newtext = srctext.replace(re, "$2");

例:http : //jsfiddle.net/entropo/tkP74/


17
  • キャプチャする必要があります .*
  • あなたは.*貪欲でないことをすることができます(しかしする必要はありません)
  • 先読みは本当に必要ありません。

    > /cow(.*?)milk/i.exec('My cow always gives milk');
    ["cow always gives milk", " always gives "]

この特定の例では、それが貪欲だった場合、最後に到達し、(おそらく)バックトラックします。
ベン

9

選ばれた答えは私にはうまくいきませんでした...うーん...

牛の後ろおよび/または牛乳の前にスペースを追加して、「常に与える」からスペースを削除します

/(?<=cow ).*(?= milk)/

ここに画像の説明を入力してください


自分の回答にコメントする必要はありません。編集するだけです。
コーディG

後読み?<=はJavascriptではサポートされていません。
マークカーペンターJr

@MarkCarpenterJrをregextester.com経由でテストすると、そのヒントが得られます。このサイトは以前の仕様のルールに基づいているようです。後読みがサポートされるようになりました。stackoverflow.com/questions/30118815/…を参照してください。このパターンは、最新のブラウザーでエラーなしにうまく機能します。代わりにこのチェッカーを試してくださいregex101.com
duduwe

@ CodyG.ahはい。とった。
duduwe 2018

8

以下のMartinho Fernandesのソリューションを使用して、必要なものを得ることができました。コードは次のとおりです。

var test = "My cow always gives milk";

var testRE = test.match("cow(.*)milk");
alert(testRE[1]);

testRE変数を配列として警告していることに気づくでしょう。これは、何らかの理由でtestREが配列として返されるためです。からの出力:

My cow always gives milk

変更点:

always gives

1
おかげで、私はフィドル(jsfiddle.net/MoscaPt/g5Lngjx8/2)を追加しました。/ヨハン
Mosca Pt

4

次の正規表現を使用するだけです。

(?<=My cow\s).*?(?=\smilk)

後読み?<=はJavascriptではサポートされていません。それを行う方法でもあります。
マークカーペンターJr

JavaScriptでサポートされています。SafariとMozilla(まだ)ではサポートされていません。ChromeとOperaでのみサポートされています。
Paul Strupeikis

3

構文を考えると、正規表現は面倒で時間がかかることがわかります。あなたはすでにjavascriptを使用しているので、正規表現なしで以下を実行する方が簡単です:

const text = 'My cow always gives milk'
const start = `cow`;
const end = `milk`;
const middleText = text.split(start)[1].split(end)[0]
console.log(middleText) // prints "always gives"

2
私のために働く!とてもシンプルなので素晴らしい答えです!:)
Andrew Irwin


0

match()メソッドは、一致する文字列を検索し、Arrayオブジェクトを返します。

// Original string
var str = "My cow always gives milk";

// Using index [0] would return<br/>
// "**cow always gives milk**"
str.match(/cow(.*)milk/)**[0]**


// Using index **[1]** would return
// "**always gives**"
str.match(/cow(.*)milk/)[1]

0

仕事

2つの文字列の間の部分文字列を抽出(この2つの文字列を除く)

解決

let allText = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum";
let textBefore = "five centuries,";
let textAfter = "electronic typesetting";
var regExp = new RegExp(`(?<=${textBefore}\\s)(.+?)(?=\\s+${textAfter})`, "g");
var results = regExp.exec(allText);
if (results && results.length > 1) {
    console.log(results[0]);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.