Javascript'te iki dize arasında bir dize almak için normal ifade


166

Çok benzer gönderiler buldum, ancak burada düzenli ifademi tam olarak alamıyorum.

Diğer iki dize arasında olan bir dize döndüren normal bir ifade yazmaya çalışıyorum. Örneğin: "İnek" ve "süt" dizeleri arasında kalan ipi almak istiyorum.

İnek her zaman süt verir

dönecekti

"her zaman verir"

İşte şimdiye kadar bir araya getirdiğim ifade:

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

Ancak, bu "inek her zaman verir" dizesini döndürür.


6
Bu eski soru üzerine tökezledim ve testRE'nin neden bir dizi olduğunu açıklamak istedim. test.match, toplam eşleme olarak ilk dizine sahip bir dizi döndürür (bu nedenle, inek (. *) sütüyle eşleşen dize) ve daha sonra, ikinci bir parantez kümesi varsa (. *) gibi tüm yakalanan dizeleri sonra testRE'de olun [2]
Salketer

4
Yeni satırlar içeren bir dize üzerinde arama yapıyorsanız bu çözüm çalışmaz. Böyle bir durumda, "STRING_ONE ([\\ s \\ S] *?) STRING_TWO" kullanmalısınız. stackoverflow.com/questions/22531252/…
Michael.Lumley

Sadece referans için MDN üzerinde maç yöntemi developer.mozilla.org/en/docs/Web/JavaScript/Reference/...
vzR

Yanıtlar:


183

Bir ileri (bu (?=kısım) herhangi bir girdi tüketmez. Bu bir sıfır genişliği onaylama (şekilde sınır kontrol ve geriye ilerleme vardır).

Burada cowkısmı tüketmek için düzenli bir eşleşme istiyorsunuz . Aradaki kısmı yakalamak için bir yakalama grubu kullanırsınız (sadece desenin parantez içine almak istediğiniz kısmını koyabilirsiniz):

cow(.*)milk

Hiç gözetmene gerek yok.


26
Bunu test ettiğimde, sağlanan Regex ifadesi hem "inek" hem de "süt"
ü içeriyor

4
Bu bir adım eksik. Eşleşmenin sonucunu aldığınızda, eşleşen metnin matched[1]tamamını değil, ilk yakalama grubunun eşleşen metnini ayıklamanız gerekir matched[0].
Rory O'Kane

7
Javascript'te aslında ([\s\S]*?)bunun yerine kullanmanız gerekir (.*?).
Qian Chen

7
Bu yararlı bir teknik olmasına rağmen, IMHO bu soru için doğru cevap DEĞİLDİR çünkü @TheCascadian
Almir Campos

@AlmirCampos - Eğer yanılmıyorsam bu maçı "inek" ve "süt" ile eşleştirmeden yapmanın bir yolu yoktur (çünkü bu ikisi arasında ne olduğunu görmek istersiniz). Sorun RegEx'in kendisinde değil, daha sonra nasıl ele alacağınızdır (Rory O'Kane tarafından belirtildiği gibi). Aksi takdirde sadece çevredeki alanlar için eşleşebilirdiniz ve bu size ÇOK yanlış bir dönüş verirdi, değil mi?
sborn

69

JavaScript'te iki dize arasında bir dize almak için normal ifade

Vakaların büyük çoğunluğunda çalışacak en eksiksiz çözüm, tembel nokta eşleştirme modeline sahip bir yakalama grubu kullanmaktır . Bununla birlikte, JavaScript normal ifadesindeki bir nokta satır sonu karakterleriyle eşleşmediğinden,% 100 durumda işe yarayacak olan bir veya.[^][\s\S] / [\d\D]/[\w\W] .

ECMAScript 2018 ve daha yeni uyumlu çözüm

Destekleyen JavaScript ortamlarında ECMAScript 2018 , sdeğiştirici verir. satır sonu grafikleri de dahil olmak üzere herhangi bir karakterle eşleşmeyi ve normal ifade motoru değişken uzunluktaki görünümleri destekler. Yani, şöyle bir regex kullanabilirsiniz

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

Her iki durumda da, mevcut konum cow daha sonra 1/0 veya daha fazla boşluklacow , ardından mümkün olduğunca az 0+ karakter eşleştirilir ve tüketilir (= eşleşme değerine eklenir) ve sonra milk(herhangi biriyle 1/0 veya daha fazla beyaz boşluktan önce).

Senaryo 1: Tek satır giriş

Bu ve aşağıdaki diğer tüm senaryolar tüm JavaScript ortamları tarafından desteklenir. Yanıtın altındaki kullanım örneklerine bakın.

cow (.*?) milk

cowönce bir boşluk, sonra bir boşluk, daha sonra *?tembel bir nicelleştirici olabildiğince az olan satır sonu karakterleri dışındaki 0+ karakterleri Grup 1'de yakalanır ve ardından bir boşluk milktakip etmelidir (ve bunlar eşleştirilir ve tüketilen da ).

Senaryo 2: Çok satırlı giriş

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

Buraya, cow ve önce bir boşluk eşleştirilir, ardından mümkün olan en az 0+ karakter Grup 1 ile milkeşleştirilir ve ardından bir boşluk eşleştirilir.

Senaryo 3: Çakışan eşleşmeler

Eğer gibi bir dize varsa >>>15 text>>>67 text2>>>ve siz aradaki-2 eşleşmeleri almak gerekir >>>+number + whitespaceve >>>sen kullanamazsınız, />>>\d+\s(.*?)>>>/gnedeni sadece 1 maç bulacaksınız bu şekilde >>>daha önce 67zaten edilir tüketilen ilk maçı bulduktan sonra. Metin varlığını gerçekte "gevşetmeden" kontrol etmek için pozitif bir ileriye bakma kullanabilirsiniz (örn. Maça ekleme):

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

Bkz gösteri Online düzenli ifade veren text1vetext2 Grup olarak 1 içerikler bulundu.

Ayrıca bkz . Bir dize için çakışan tüm eşleşmeleri nasıl edinirim .

Performans hususları

.*?Normal ifade desenlerindeki tembel nokta eşleme deseni ( ), çok uzun bir giriş verilirse kod yürütülmesini yavaşlatabilir. Birçok durumda, döngü çözme tekniği daha büyük ölçüde yardımcı olur. Arasındaki tüm kapmak için çalışılıyor cowve milkgelen "Their\ncow\ngives\nmore\nmilk"biz sadece ile başlamayan tüm satırları eşleşmesi gerekir görüyoruz milkyerine, böylece cow\n([\s\S]*?)\nmilkbiz kullanabilirsiniz:

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

Regex demosuna bakın (varsa \r\n, kullanın /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm). Bu küçük test dizgisi ile performans artışı göz ardı edilebilir, ancak çok büyük metinlerde farkı hissedeceksiniz (özellikle satırlar uzunsa ve satır sonları çok sayıda değilse).

JavaScript'te örnek regex kullanımı:

//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);

Modern String#matchAllyöntemi kullanma

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

İşte inek ve süt arasındaki şeyi kaplayacak bir regex (öncü / sondaki boşluk olmadan):

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

Bir örnek: http://jsfiddle.net/entropo/tkP74/


17
  • Yakalamanız gerekiyor .*
  • .*Gereksiz hale getirebilirsin (ama yapmak zorunda değilsin)
  • Gerçekten ileriye bakmaya gerek yok.

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

Bu özel durumda, eğer açgözlü olsaydı, sonuna ve geriye doğru (muhtemelen) ulaşırdı.
Ben

9

Seçilen cevap benim için işe yaramadı ... hmm ...

Sadece inek ve / veya sütten önce "her zaman verir"

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

resim açıklamasını buraya girin


Kendi cevabınıza yorum yapmanız gerekmez, sadece düzenleyin.
Cody

Arkasına Bak ?<=Javascript'te desteklenmez.
Mark Carpenter Jr

@ MarkCarpenterJr regextester.com üzerinden test ettiyseniz , bu ipucunu alacaksınız. Görünüşe göre site kurallarını daha eski spesifikasyonlara dayandırmıştır. Lookbehind artık desteklenmektedir. Bkz. Stackoverflow.com/questions/30118815/… Ve desen hatasız modern tarayıcılarla iyi çalışır. Bunun yerine bu denetleyiciyi deneyin regex101.com
duduwe

@ CodyG.ah evet. anladım.
duduwe

8

Aşağıdaki Martinho Fernandes çözümünü kullanarak ihtiyacım olanı elde edebildim. Kod:

var test = "My cow always gives milk";

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

TestRE değişkenini bir dizi olarak uyartığımı fark edeceksiniz. Bunun nedeni testRE'nin bir nedenle bir dizi olarak geri dönmesidir. Çıktı:

My cow always gives milk

Şuna dönüşür:

always gives

1
Teşekkürler, bunun için bir keman ( jsfiddle.net/MoscaPt/g5Lngjx8/2 ) ekledim . / Johan
Mosca Pt

4

Aşağıdaki normal ifadeyi kullanmanız yeterlidir:

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

Arkasına Bak ?<=Javascript'te desteklenmez. Gerçi bunu yapmanın yolu olurdu.
Mark Carpenter Jr

JavaScript'te desteklenir. Safari ve Mozilla'da (henüz), yalnızca Chrome ve Opera'da desteklenmemektedir.
Paul Strupeikis

3

Sözdizimi göz önüne alındığında regex'in sıkıcı ve zaman alıcı olduğunu düşünüyorum. Zaten javascript kullandığınızdan, regex olmadan aşağıdakileri yapmak daha kolaydır:

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
Benim için çalışıyor! harika bir cevap çünkü gerçekten çok basit! :)
Andrew Irwin


0

Method match (), bir dizede eşleşme arar ve bir Array nesnesi döndürür.

// 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

Görev

İki dize arasındaki alt dizeyi ayıkla (bu iki dize hariç)

Çözüm

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]);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.