Regex pour remplacer tous les premiers caractères de tabulation, chacun avec un seul espace [dupliquer]

Nov 24 2020

Je recherche une expression régulière pour remplacer tous les caractères de tabulation principaux par un seul espace (un espace pour chaque caractère de tabulation principal.

// 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"

Voyez ceci dans un violon js: https://jsfiddle.net/onebcvu4/2/

Réponse D travaille pour moi.

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

Mais je ne comprends pas vraiment pourquoi. Surtout parce que, selon la documentation MDN , l'indicateur global (G) doit être ignoré lorsqu'il est utilisé avec un indicateur collant.

Une expression régulière définie à la fois comme persistante et globale ignore l'indicateur global.

Quelqu'un peut-il clarifier ou fournir une autre solution qui fonctionne?

Réponses

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

Votre réponse D fonctionne (et est assez intelligente) parce que get y ne sont pas exclusives, mais il était raisonnable de penser qu'elles le seraient. Tous les détails sont dans la spécification ici et ici , mais fondamentalement, le gfait replacerépéter tant qu'il y a une correspondance, et ysignifie que A) l'expression ne correspond qu'à lastIndex(qui vaut 0 par défaut), et B) lastIndexn'est pas mis à jour. Vous faites donc correspondre à plusieurs reprises un \tat lastIndexet le remplacez jusqu'à ce que vous manquiez de \tat lastIndex. Très intelligent.

Si vous ne voulez pas utiliser celui-là, vous pouvez également le faire avec une alternance et un regard positif derrière:

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

Exemple en direct:

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

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

Ou si vous êtes d'accord pour passer un rappel à replace, c'est plus simple et n'a pas besoin de regarder en arrière (ce qui est relativement nouveau, ES2018): faites correspondre tous les \tcaractères de début et remplacez-les par une chaîne d'espaces de même longueur:

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

Exemple en direct:

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