Regex, aby zastąpić wszystkie początkowe znaki tabulacji, każdy z pojedynczą spacją [duplikat]

Nov 24 2020

Szukam wyrażenia regularnego, które zastąpi wszystkie początkowe znaki tabulacji pojedynczą spacją (po jednej spacji dla każdego wiodącego znaku tabulacji.

// input text with two leading tab characters and two tab characters elsewhere in the text
var input="     Some text       containing tabs";

// A:
console.log(input.replace(/\t/g, "LEADING_TAB_"));  
// prints: "LEADING_TAB_LEADING_TAB_Some textLEADING_TAB_LEADING_TAB_containing tabs"

// B:
console.log(input.replace(/\t/, "LEADING_TAB_"));  
// prints: "LEADING_TAB_   Some text       containing tabs"

// C:
console.log(input.replace(/^(\t)*/, "LEADING_TAB_"));  
// prints: "LEADING_TAB_Some text      containing tabs"

// D:
console.log(input.replace(/\t/gy, "LEADING_TAB_"));  
// prints: "LEADING_TAB_LEADING_TAB_Some text      containing tabs"

// E:
console.log(input.replace(/\t/y, "LEADING_TAB_"));  
// prints: "LEADING_TAB_   Some text       containing tabs"

Zobacz to na skrzypcach js: https://jsfiddle.net/onebcvu4/2/

Odpowiedź D działa dla mnie.

input.replace(/\t/gy, " ")

Ale naprawdę nie rozumiem, dlaczego. Zwłaszcza, że ​​zgodnie z dokumentacją MDN flagę globalną (G) należy ignorować, gdy jest używana z flagą sticky.

Wyrażenie regularne zdefiniowane jako trwałe i globalne ignoruje flagę globalną.

Czy ktoś może wyjaśnić lub zapewnić inne działające rozwiązanie?

Odpowiedzi

2 T.J.Crowder Nov 24 2020 at 14:46

Twoja odpowiedź D działa (i jest całkiem sprytna), ponieważ gi y nie jest wyłączna, ale rozsądnie było sądzić, że tak będzie. Pełne szczegóły znajdują się w specyfikacji tutaj i tutaj , ale zasadniczo gmarki replacepowtarzają się tak długo, jak długo istnieje zgodność, co yoznacza, że ​​A) wyrażenie pasuje tylko w lastIndex(domyślnie 0), a B) lastIndexnie jest aktualizowane. Więc wielokrotnie dopasowujesz \tat lastIndexi zastępujesz go, aż zabraknie \tat lastIndex. Bardzo mądry.

Jeśli nie chcesz tego używać, możesz to również zrobić z naprzemiennym spojrzeniem i pozytywnym spojrzeniem za:

const result = input.replace(/(?:^\t|(?<=^\t*)\t)/g, " ");

Przykład na żywo:

const input = "\t\tSome text\t\tcontaining tabs";
const result = input.replace(/(?:^\t|(?<=^\t*)\t)/g, " ");

console.log(JSON.stringify(result));

Lub jeśli replacenie przeszkadza ci przekazywanie wywołania zwrotnego do , jest to prostsze i nie wymaga wyszukiwania wstecznego (co jest stosunkowo nowe, ES2018): Dopasuj wszystkie wiodące \tznaki i zastąp ciągiem spacji o tej samej długości:

const result = input.replace(/^(\t+)/, match => " ".repeat(match.length));

Przykład na żywo:

const input = "\t\tSome text\t\tcontaining tabs";
const result = input.replace(/^(\t+)/, match => " ".repeat(match.length));
console.log(JSON.stringify(result));