Mengembalikan posisi pertandingan regex () di Javascript?

154

Apakah ada cara untuk mengambil posisi karakter (mulai) di dalam string hasil pertandingan regex () di Javascript?

stagas
sumber

Jawaban:

225

execmengembalikan objek dengan indexproperti:

var match = /bar/.exec("foobar");
if (match) {
    console.log("match found at " + match.index);
}

Dan untuk beberapa pertandingan:

var re = /bar/g,
    str = "foobarfoobar";
while ((match = re.exec(str)) != null) {
    console.log("match found at " + match.index);
}

Gumbo
sumber
5
Terima kasih atas bantuan Anda! Bisakah Anda memberi tahu saya juga bagaimana cara menemukan indeks beberapa pertandingan?
stagas
9
Catatan: menggunakan resebagai variabel, dan menambahkan gpengubah sama-sama penting! Kalau tidak, Anda akan mendapatkan loop tanpa akhir.
oriadam
1
@ OnurYıldırım - inilah jsfiddle yang berfungsi ... Saya telah mengujinya sepanjang jalan kembali ke IE5 ... berfungsi dengan baik: jsfiddle.net/6uwn1vof
Jimbo Jonny
1
@JimboJonny, hm yah aku belajar sesuatu yang baru. Test case saya kembali undefined. jsfiddle.net/6uwn1vof/2 yang bukan contoh pencarian seperti milik Anda.
Onur Yıldırım
1
@ OnurYıldırım - Hapus gbendera dan itu akan berfungsi. Karena matchini adalah fungsi dari string, bukan regex yang tidak boleh stateful seperti exec, jadi itu hanya memperlakukannya seperti exec(yaitu memiliki properti indeks) jika Anda tidak mencari kecocokan global ... karena dengan demikian statefulness tidak masalah .
Jimbo Jonny
60

Inilah yang saya pikirkan:

// Finds starting and ending positions of quoted text
// in double or single quotes with escape char support like \" \'
var str = "this is a \"quoted\" string as you can 'read'";

var patt = /'((?:\\.|[^'])*)'|"((?:\\.|[^"])*)"/igm;

while (match = patt.exec(str)) {
  console.log(match.index + ' ' + patt.lastIndex);
}

stagas
sumber
18
match.index + match[0].lengthjuga berfungsi untuk posisi akhir.
Beni Cherniavsky-Paskin
benar-benar baik - perbandingannya di sini
Louis Maddox
1
@ BeniCherniavsky-Paskin, bukankah posisi akhirnya match.index + match[0].length - 1?
David
1
@ David, maksud saya posisi akhir eksklusif, seperti diambil misalnya oleh .slice()dan .substring(). Akhir inklusif akan menjadi 1 kurang seperti yang Anda katakan. (Berhati-hatilah karena inklusif biasanya berarti indeks pertandingan terakhir di dalam pertandingan, kecuali pertandingan kosong di mana pertandingan 1 sebelum pertandingan dan mungkin berada di -1luar string sepenuhnya untuk pertandingan kosong di awal ...)
Beni Cherniavsky-Paskin
16

Dari developer.mozilla.org dokumen tentang .match()metode String :

Array yang dikembalikan memiliki properti input tambahan, yang berisi string asli yang diuraikan. Sebagai tambahan, ia memiliki properti indeks, yang mewakili indeks kecocokan berbasis nol di string .

Ketika berhadapan dengan regex non-global (yaitu, tidak ada gbendera pada regex Anda), nilai yang dikembalikan oleh .match()memilikiindex properti ... yang harus Anda lakukan adalah mengaksesnya.

var index = str.match(/regex/).index;

Berikut adalah contoh yang menunjukkan itu berfungsi juga:

var str = 'my string here';

var index = str.match(/here/).index;

alert(index); // <- 10

Saya telah berhasil menguji ini semua jalan kembali ke IE5.

Jimbo Jonny
sumber
6

Anda dapat menggunakan searchmetode Stringobjek. Ini hanya akan berfungsi untuk pertandingan pertama, tetapi sebaliknya akan melakukan apa yang Anda gambarkan. Sebagai contoh:

"How are you?".search(/are/);
// 4
Jimmy Cuadra
sumber
6

Ini adalah fitur keren yang saya temukan baru-baru ini, saya mencoba ini di konsol dan sepertinya berfungsi:

var text = "border-bottom-left-radius";

var newText = text.replace(/-/g,function(match, index){
    return " " + index + " ";
});

Yang dikembalikan: "batas 6 bawah 13 kiri 18 radius"

Jadi sepertinya ini yang Anda cari.

felipeab
sumber
6
berhati-hatilah karena fungsi penggantian juga menambahkan kelompok tangkap, jadi perhatikan bahwa itu selalu entri kedua ke terakhir dalam fungsi penggantian argumentsyang merupakan posisi. Bukan "argumen kedua". Argumen fungsi adalah "pertandingan penuh, grup1, grup2, ...., indeks pertandingan, string penuh cocok dengan"
Mike 'Pomax' Kamermans
1

Anggota ini fn mengembalikan array posisi berbasis 0, jika ada, dari kata input di dalam objek String

String.prototype.matching_positions = function( _word, _case_sensitive, _whole_words, _multiline )
{
   /*besides '_word' param, others are flags (0|1)*/
   var _match_pattern = "g"+(_case_sensitive?"i":"")+(_multiline?"m":"") ;
   var _bound = _whole_words ? "\\b" : "" ;
   var _re = new RegExp( _bound+_word+_bound, _match_pattern );
   var _pos = [], _chunk, _index = 0 ;

   while( true )
   {
      _chunk = _re.exec( this ) ;
      if ( _chunk == null ) break ;
      _pos.push( _chunk['index'] ) ;
      _re.lastIndex = _chunk['index']+1 ;
   }

   return _pos ;
}

Sekarang coba

var _sentence = "What do doers want ? What do doers need ?" ;
var _word = "do" ;
console.log( _sentence.matching_positions( _word, 1, 0, 0 ) );
console.log( _sentence.matching_positions( _word, 1, 1, 0 ) );

Anda juga dapat memasukkan ekspresi reguler:

var _second = "z^2+2z-1" ;
console.log( _second.matching_positions( "[0-9]\z+", 0, 0, 0 ) );

Di sini kita mendapatkan indeks posisi istilah linear.

Sandro Rosa
sumber
1
var str = "The rain in SPAIN stays mainly in the plain";

function searchIndex(str, searchValue, isCaseSensitive) {
  var modifiers = isCaseSensitive ? 'gi' : 'g';
  var regExpValue = new RegExp(searchValue, modifiers);
  var matches = [];
  var startIndex = 0;
  var arr = str.match(regExpValue);

  [].forEach.call(arr, function(element) {
    startIndex = str.indexOf(element, startIndex);
    matches.push(startIndex++);
  });

  return matches;
}

console.log(searchIndex(str, 'ain', true));
Yaroslav
sumber
Ini salah. str.indexOfdi sini hanya menemukan kemunculan teks berikutnya yang ditangkap oleh pertandingan, yang belum tentu cocok. JS regex mendukung kondisi pada teks di luar tangkapan dengan lookahead. Misalnya searchIndex("foobarfoobaz", "foo(?=baz)", true)harus memberi [6], bukan [0].
rakslice
why `[] .forEach.call (arr, function (element)` why tidak arr.forEach atau arr.map
Ankit Kumar
1

Di browser modern, Anda dapat melakukannya dengan string.matchAll () .

Manfaat dari pendekatan ini vs RegExp.exec()adalah bahwa ia tidak bergantung pada regex yang stateful, seperti dalam jawaban @ Gumbo .

let regexp = /bar/g;
let str = 'foobarfoobar';

let matches = [...str.matchAll(regexp)];
matches.forEach((match) => {
    console.log("match found at " + match.index);
});

brismut
sumber
-1
function trimRegex(str, regex){
    return str.substr(str.match(regex).index).split('').reverse().join('').substr(str.match(regex).index).split('').reverse().join('');
}

let test = '||ab||cd||';
trimRegex(test, /[^|]/);
console.log(test); //output: ab||cd

atau

function trimChar(str, trim, req){
    let regex = new RegExp('[^'+trim+']');
    return str.substr(str.match(regex).index).split('').reverse().join('').substr(str.match(regex).index).split('').reverse().join('');
}

let test = '||ab||cd||';
trimChar(test, '|');
console.log(test); //output: ab||cd
SwiftNinjaPro
sumber