Start · Sprachen · JavaScript · Referenz · RegExp: lastIndex

RegExp: lastIndex

Eigenschaft

Die beschreibbare Eigenschaft <code>lastIndex</code> einer RegExp-Instanz gibt den Index an, ab dem die nächste Suche mit dem Flag <code>g</code> oder <code>y</code> beginnt.

seit JavaScript ES1 (Baseline: alle Browser) Kategorie: method-property

Signatur

RegExp.prototype.lastIndex

Beschreibung

lastIndex ist eine eigene Dateneigenschaft jeder RegExp-Instanz. Sie liegt also direkt auf dem Objekt, nicht auf dem Prototyp, und ist beschreibbar, aber nicht aufzählbar und nicht konfigurierbar. Beim Erzeugen eines regulären Ausdrucks steht sie auf 0. Ausgewertet wird sie nur, wenn der Ausdruck das Flag g (global) oder y (sticky) trägt. Ohne diese Flags beginnt die Suche immer bei Index 0, und lastIndex bleibt unverändert.

So verhalten sich RegExp.prototype.exec() und RegExp.prototype.test() bei gesetztem g oder y:

  • Die Suche beginnt an der Position lastIndex.
  • Bei einem Treffer wird lastIndex auf den Index direkt nach dem Treffer gesetzt.
  • Gibt es keinen Treffer oder ist lastIndex größer als die Länge der Zeichenkette, wird lastIndex auf 0 zurückgesetzt, und die Methode liefert null bzw. false.
  • Mit dem Flag y muss der Treffer genau bei lastIndex beginnen. Die Suche springt nicht weiter nach vorn.

In der Praxis braucht man lastIndex vor allem für zwei Dinge: um in einer Schleife alle Treffer schrittweise mit exec() abzuarbeiten und um mit dem Flag y Tokenizer oder Parser zu bauen, die gezielt an einer bestimmten Position weiterlesen. Da der Zustand im RegExp-Objekt selbst gespeichert wird, führt ein wiederverwendeter globaler Ausdruck schnell zu schwer auffindbaren Fehlern (siehe Hinweise).

Rückgabewert

Typ
number
Beschreibung
Eine nicht-negative ganze Zahl: die Position, an der die nächste Suche beginnt. Zugewiesene Werte werden bei der Suche mit ToLength in eine ganze Zahl umgewandelt.

Beispiele

Alle Treffer mit exec() und lastIndex durchlaufen

const re = /\d+/g;
const text = 'Artikel 12, Menge 7, Preis 199';
let match;

while ((match = re.exec(text)) !== null) {
  console.log(`${match[0]} gefunden bei ${match.index}, lastIndex jetzt ${re.lastIndex}`);
}
console.log('Nach der Schleife:', re.lastIndex);
12 gefunden bei 8, lastIndex jetzt 10 7 gefunden bei 18, lastIndex jetzt 19 199 gefunden bei 27, lastIndex jetzt 30 Nach der Schleife: 0

Fallstrick: test() mit globalem Ausdruck liefert abwechselnd true/false

const istZahl = /^\d+$/g;

console.log(istZahl.test('42'), istZahl.lastIndex);
console.log(istZahl.test('42'), istZahl.lastIndex); // Suche beginnt bei 2!

// Abhilfe: g-Flag weglassen oder lastIndex zurücksetzen
istZahl.lastIndex = 0;
console.log(istZahl.test('42'));
true 2 false 0 true

Einfacher Tokenizer mit Sticky-Flag y

const tokenize = (input) => {
  const regeln = [
    ['ZAHL', /\d+/y],
    ['OP', /[+\-*\/]/y],
    ['LEER', /\s+/y],
  ];
  const tokens = [];
  let pos = 0;

  while (pos < input.length) {
    let treffer = false;
    for (const [typ, re] of regeln) {
      re.lastIndex = pos; // exakt an der aktuellen Position prüfen
      const m = re.exec(input);
      if (m) {
        if (typ !== 'LEER') tokens.push({ typ, wert: m[0] });
        pos = re.lastIndex;
        treffer = true;
        break;
      }
    }
    if (!treffer) throw new SyntaxError(`Unerwartetes Zeichen bei ${pos}`);
  }
  return tokens;
};

console.log(tokenize('12 + 3*4'));
[ { typ: 'ZAHL', wert: '12' }, { typ: 'OP', wert: '+' }, { typ: 'ZAHL', wert: '3' }, { typ: 'OP', wert: '*' }, { typ: 'ZAHL', wert: '4' } ]

Suche gezielt ab einer Position starten

const re = /ab/g;
const s = 'ab--ab--ab';

re.lastIndex = 3;
const m = re.exec(s);
console.log(m.index, re.lastIndex);
4 6

// Wichtig · Fallstricke

  • Zustandsbehaftete Ausdrücke: Ein RegExp-Literal mit g oder y, das in einer Konstanten auf Modulebene steht und mehrfach mit test() oder exec() benutzt wird, merkt sich lastIndex über alle Aufrufe hinweg. Dadurch liefert es abwechselnd true und false. Für reine Ja/Nein-Prüfungen lässt man das g-Flag daher weg.
  • Leere Treffer: Passt ein Muster auf eine leere Zeichenkette (z. B. /a*/g), bleibt lastIndex bei einer eigenen exec()-Schleife stehen, und die Schleife läuft endlos. In diesem Fall muss man re.lastIndex++ selbst hochzählen oder gleich matchAll() verwenden.
  • String.prototype.match() mit g, replace(), replaceAll() und split() setzen lastIndex vorher intern auf 0. matchAll() arbeitet auf einer Kopie des Ausdrucks und verändert das Original nicht.
  • String.prototype.search() ignoriert lastIndex und stellt den ursprünglichen Wert danach wieder her.
  • Mit dem Flag u oder v zählt lastIndex weiterhin in UTF-16-Codeeinheiten, nicht in Unicode-Codepunkten.
  • Die Eigenschaft wird von allen Browsern und von Node.js unterstützt. Das Flag y gibt es seit ES2015.