Positionen einer Regex-Übereinstimmung () in Javascript zurückgeben?

154

Gibt es eine Möglichkeit, die (Start-) Zeichenpositionen innerhalb einer Zeichenfolge der Ergebnisse einer Regex-Übereinstimmung () in Javascript abzurufen?

stagas
quelle

Antworten:

225

execGibt ein Objekt mit einer indexEigenschaft zurück:

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

Und für mehrere Spiele:

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

Gumbo
quelle
5
Danke für Ihre Hilfe! Können Sie mir auch sagen, wie ich die Indizes mehrerer Übereinstimmungen finde?
Stagas
9
Hinweis: Die Verwendung von reals Variable und das Hinzufügen des gModifikators sind beide entscheidend! Andernfalls erhalten Sie eine Endlosschleife.
Oriadam
1
@ OnurYıldırım - hier ist eine jsfiddle davon funktioniert ... Ich habe es bis zum IE5 getestet ... funktioniert großartig: jsfiddle.net/6uwn1vof
Jimbo Jonny
1
@ JimboJonny, hm gut, ich habe etwas Neues gelernt. Mein Testfall kehrt zurück undefined. jsfiddle.net/6uwn1vof/2, das kein suchähnliches Beispiel wie Ihres ist.
Onur Yıldırım
1
@ OnurYıldırım - Entferne die gFlagge und es wird funktionieren. Da matches sich um eine Funktion des Strings handelt, nicht um den regulären Ausdruck, kann er nicht statusbehaftet sein. Daher execwird er nur so behandelt exec(dh hat eine Indexeigenschaft), wenn Sie nicht nach einer globalen Übereinstimmung suchen ... denn dann spielt Statefulness keine Rolle .
Jimbo Jonny
60

Folgendes habe ich mir ausgedacht:

// 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
quelle
17
match.index + match[0].lengthfunktioniert auch für die Endposition.
Beni Cherniavsky-Paskin
wirklich schön - Vergleich hier
Louis Maddox
1
@ BeniCherniavsky-Paskin, wäre die Endposition nicht match.index + match[0].length - 1?
David
1
@ David, ich meinte exklusive Endposition, wie zB von .slice()und eingenommen .substring(). Inklusives Ende wäre 1 weniger, wie Sie sagen. (Seien Sie vorsichtig, dass inklusive normalerweise den Index des letzten Zeichens innerhalb des Spiels bedeutet, es sei denn, es ist ein leeres Spiel, bei dem es 1 vor dem Spiel ist und möglicherweise zu -1Beginn außerhalb des Strings für ein leeres Spiel liegt ...)
Beni Cherniavsky-Paskin
16

Aus den Dokumenten von developer.mozilla.org zur String- .match()Methode:

Das zurückgegebene Array verfügt über eine zusätzliche Eingabeeigenschaft, die die ursprüngliche Zeichenfolge enthält, die analysiert wurde. Darüber hinaus verfügt es über eine Indexeigenschaft, die den auf Null basierenden Index der Übereinstimmung in der Zeichenfolge darstellt .

Wenn Sie sich mit einem nicht globalen regulären Ausdruck befassen (dh kein gFlag in Ihrem regulären Ausdruck), hat der von zurückgegebene Wert .match()eine indexEigenschaft ... Sie müssen lediglich darauf zugreifen.

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

Hier ist ein Beispiel, das zeigt, wie es auch funktioniert:

var str = 'my string here';

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

alert(index); // <- 10

Ich habe dies erfolgreich bis zum IE5 getestet.

Jimbo Jonny
quelle
6

Sie können die searchMethode des StringObjekts verwenden. Dies funktioniert nur für das erste Spiel, aber ansonsten wird das getan, was Sie beschreiben. Beispielsweise:

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

Hier ist eine coole Funktion, die ich kürzlich entdeckt habe. Ich habe sie auf der Konsole ausprobiert und sie scheint zu funktionieren:

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

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

Was zurückkam: "Rand 6 unten 13 links 18 Radius"

Das scheint also das zu sein, wonach Sie suchen.

felipeab
quelle
6
Beachten Sie jedoch, dass durch Ersatzfunktionen auch Erfassungsgruppen hinzugefügt werden. Beachten Sie daher, dass immer der vorletzte Eintrag in der Ersatzfunktion argumentsdie Position ist. Nicht "das zweite Argument". Die Funktionsargumente sind "vollständige Übereinstimmung, Gruppe1, Gruppe2, ...., Übereinstimmungsindex, vollständige Zeichenfolge, mit der verglichen wird"
Mike 'Pomax' Kamermans
1

Dieses Element fn gibt gegebenenfalls ein Array von 0-basierten Positionen des Eingabeworts innerhalb des String-Objekts zurück

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 ;
}

Versuchen Sie es jetzt

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

Sie können auch reguläre Ausdrücke eingeben:

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

Hier erhält man den Positionsindex des linearen Terms.

Sandro Rosa
quelle
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));
Jaroslaw
quelle
Das ist falsch. str.indexOfHier wird nur das nächste Vorkommen des von der Übereinstimmung erfassten Textes gefunden, der nicht unbedingt die Übereinstimmung ist. JS Regex unterstützt Bedingungen für Text außerhalb der Erfassung mit Lookahead. Zum Beispiel searchIndex("foobarfoobaz", "foo(?=baz)", true)geben soll [6], nicht [0].
Rakslice
warum `[] .forEach.call (arr, function (element)` warum nicht arr.forEach oder arr.map
Ankit Kumar
1

In modernen Browsern können Sie dies mit string.matchAll () erreichen .

Der Vorteil dieses Ansatzes gegenüber RegExp.exec()ist, dass er nicht davon abhängt, dass der reguläre Ausdruck zustandsbehaftet ist, wie in der Antwort von @ Gumbo .

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

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

Brismut
quelle
-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

oder

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
quelle