Pertanyaan Bagaimana Anda mengakses grup yang cocok dalam ekspresi reguler JavaScript?


Saya ingin mencocokkan sebagian dari string menggunakan ekspresi reguler lalu akses substring yang telah disisipkan:

var myString = "something format_abc"; // I want "abc"

var arr = /(?:^|\s)format_(.*?)(?:\s|$)/.exec(myString);

console.log(arr);     // Prints: [" format_abc", "abc"] .. so far so good.
console.log(arr[1]);  // Prints: undefined  (???)
console.log(arr[0]);  // Prints: format_undefined (!!!)

Apa yang saya lakukan salah?


Saya telah menemukan bahwa tidak ada yang salah dengan kode ekspresi reguler di atas: string sebenarnya yang saya uji terhadap adalah ini:

"date format_%A"

Melaporkan bahwa "% A" tidak terdefinisi tampaknya merupakan perilaku yang sangat aneh, tetapi tidak secara langsung terkait dengan pertanyaan ini, jadi saya telah membuka yang baru, Mengapa substring yang cocok mengembalikan "tidak ditentukan" dalam JavaScript?.


Masalahnya adalah itu console.log mengambil parameternya seperti a printf pernyataan, dan karena string saya sedang login ("%A") memiliki nilai khusus, ia berusaha mencari nilai parameter berikutnya.


1019
2018-01-11 07:21


asal


Jawaban:


Anda dapat mengakses grup penangkap seperti ini:

var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
var match = myRegexp.exec(myString);
console.log(match[1]); // abc

Dan jika ada beberapa kecocokan, Anda dapat mengulanginya:

var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
match = myRegexp.exec(myString);
while (match != null) {
  // matched text: match[0]
  // match start: match.index
  // capturing group n: match[n]
  console.log(match[0])
  match = myRegexp.exec(myString);
}


1304
2018-01-11 07:26



Berikut ini metode yang dapat Anda gunakan untuk mendapatkan nKelompok menangkap th untuk setiap pertandingan:

function getMatches(string, regex, index) {
  index || (index = 1); // default to the first capturing group
  var matches = [];
  var match;
  while (match = regex.exec(string)) {
    matches.push(match[index]);
  }
  return matches;
}


// Example :
var myString = 'something format_abc something format_def something format_ghi';
var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g;

// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);

// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);


152
2018-01-08 08:26



var myString = "something format_abc";
var arr = myString.match(/\bformat_(.*?)\b/);
console.log(arr[0] + " " + arr[1]);

Itu \b tidak persis sama. (Itu berhasil --format_foo/, tetapi tidak berfungsi format_a_b) Tapi saya ingin menunjukkan alternatif untuk ekspresi Anda, yang baik-baik saja. Tentu saja, itu match panggilan adalah hal yang penting.


48
2018-01-11 09:10



Sehubungan dengan contoh kurung multi-pertandingan di atas, saya mencari jawaban di sini setelah tidak mendapatkan apa yang saya inginkan dari:

var matches = mystring.match(/(?:neededToMatchButNotWantedInResult)(matchWanted)/igm);

Setelah melihat panggilan fungsi yang sedikit berbelit-belit dengan sementara dan .push () di atas, saya sadar bahwa masalahnya dapat diselesaikan dengan sangat elegan dengan mystring.replace () sebagai gantinya (mengganti TIDAK pada intinya, dan bahkan tidak dilakukan , CLEAN, opsi panggilan fungsi rekursif built-in untuk parameter kedua adalah!):

var yourstring = 'something format_abc something format_def something format_ghi';

var matches = [];
yourstring.replace(/format_([^\s]+)/igm, function(m, p1){ matches.push(p1); } );

Setelah ini, saya tidak berpikir saya akan menggunakan .match () untuk hampir tidak pernah ada lagi.


19
2017-07-17 04:53



Sintaks Anda mungkin bukan yang terbaik untuk dijaga. FF / Gecko mendefinisikan RegExp sebagai perpanjangan dari Fungsi.
(FF2 pergi sejauh typeof(/pattern/) == 'function')

Tampaknya ini khusus untuk FF - IE, Opera, dan Chrome semua membuang pengecualian untuk itu.

Sebaliknya, gunakan salah satu metode yang disebutkan sebelumnya oleh orang lain: RegExp#exec atau String#match.
Mereka menawarkan hasil yang sama:

var regex = /(?:^|\s)format_(.*?)(?:\s|$)/;
var input = "something format_abc";

regex(input);        //=> [" format_abc", "abc"]
regex.exec(input);   //=> [" format_abc", "abc"]
input.match(regex);  //=> [" format_abc", "abc"]

15
2018-01-11 12:55



Last but not least, saya menemukan bahwa satu baris kode yang bekerja dengan baik untuk saya (JS ES6):

var reg = /#([\S]+)/igm; //get hashtags
var string = 'mi alegría es total! \n#fiestasdefindeaño #PadreHijo #buenosmomentos #france #paris';

var matches = (string.match(reg) || []).map(e => e.replace(reg, '$1'));
console.log(matches);

ini akan kembali: [fiestasdefindeaño, PadreHijo, buenosmomentos, france, paris]


9
2018-01-03 14:40



Terminologi yang digunakan dalam jawaban ini:

  • Pertandingan menunjukkan hasil menjalankan pola RegEx Anda terhadap string Anda seperti ini: someString.match(regexPattern).
  • Pola yang cocok menunjukkan semua bagian yang cocok dari string input, yang semuanya berada di dalam pertandingan larik. Ini semua adalah contoh dari pola Anda di dalam string input.
  • Grup yang cocok menunjukkan semua kelompok untuk ditangkap, ditentukan dalam pola RegEx. (Pola di dalam tanda kurung, seperti ini: /format_(.*?)/g, dimana (.*?) akan menjadi grup yang cocok.) Ini berada di dalam pola yang cocok.

Deskripsi

Untuk mendapatkan akses ke grup yang cocok, di masing-masing pola yang cocok, Anda memerlukan fungsi atau sesuatu yang serupa dengan iterate di atas pertandingan. Ada beberapa cara yang dapat Anda lakukan, seperti yang ditunjukkan oleh banyak jawaban lainnya. Sebagian besar jawaban lainnya menggunakan loop sementara untuk iterasi atas semua pola yang cocok, tapi saya pikir kita semua tahu potensi bahaya dengan pendekatan itu. Ini perlu untuk pertandingan melawan new RegExp() bukan hanya pola itu sendiri, yang hanya disebutkan dalam komentar. Ini karena .exec() metode berperilaku serupa dengan fungsi generator - berhenti setiap kali ada kecocokan, tapi tetap memilikinya .lastIndex untuk melanjutkan dari sana di depan .exec() panggilan.

Contoh kode

Di bawah ini adalah contoh fungsi searchString yang mengembalikan sebuah Array dari semua pola yang cocok, dimana masing-masing match adalah Array dengan semua yang mengandung grup yang cocok. Alih-alih menggunakan loop sementara, saya telah memberikan contoh menggunakan keduanya Array.prototype.map() berfungsi serta cara yang lebih berkinerja - menggunakan dataran for-suka.

Versi ringkas (kurang kode, lebih banyak gula sintaksis)

Ini kurang berkinerja karena mereka pada dasarnya menerapkan forEach-buka bukan yang lebih cepat for-suka.

// Concise ES6/ES2015 syntax
const searchString = 
    (string, pattern) => 
        string
        .match(new RegExp(pattern.source, pattern.flags))
        .map(match => 
            new RegExp(pattern.source, pattern.flags)
            .exec(match));

// Or if you will, with ES5 syntax
function searchString(string, pattern) {
    return string
        .match(new RegExp(pattern.source, pattern.flags))
        .map(match =>
            new RegExp(pattern.source, pattern.flags)
            .exec(match));
}

let string = "something format_abc",
    pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;

let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag

Performant version (lebih banyak kode, lebih sedikit syntactic sugar)

// Performant ES6/ES2015 syntax
const searchString = (string, pattern) => {
    let result = [];

    const matches = string.match(new RegExp(pattern.source, pattern.flags));

    for (let i = 0; i < matches.length; i++) {
        result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
    }

    return result;
};

// Same thing, but with ES5 syntax
function searchString(string, pattern) {
    var result = [];

    var matches = string.match(new RegExp(pattern.source, pattern.flags));

    for (var i = 0; i < matches.length; i++) {
        result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
    }

    return result;
}

let string = "something format_abc",
    pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;

let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag

Saya belum membandingkan alternatif-alternatif ini dengan yang sebelumnya disebutkan dalam jawaban lainnya, tetapi saya ragu pendekatan ini kurang berkinerja dan kurang aman dari yang lain.


7
2017-08-23 22:36



Satu liner yang praktis hanya jika Anda memiliki sepasang tanda kurung:

while ( ( match = myRegex.exec( myStr ) ) && matches.push( match[1] ) ) {};

5
2017-07-12 15:41



Tidak perlu memanggil exec metode! Anda dapat menggunakan metode "cocok" langsung pada string. Jangan lupa tanda kurung.

var str = "This is cool";
var matches = str.match(/(This is)( cool)$/);
console.log( JSON.stringify(matches) ); // will print ["This is cool","This is"," cool"] or something like that...

Posisi 0 memiliki string dengan semua hasil. Posisi 1 memiliki pertandingan pertama diwakili oleh tanda kurung, dan posisi 2 memiliki pertandingan kedua yang diisolasi dalam tanda kurung Anda. Tanda kurung tersusun rumit, jadi berhati-hatilah!


5
2018-06-19 19:47



Menggunakan kode Anda:

console.log(arr[1]);  // prints: abc
console.log(arr[0]);  // prints:  format_abc

Edit: Safari 3, jika itu penting.


4
2018-01-11 07:27