Renvoyer les positions d'une correspondance regex () en Javascript?

154

Existe-t-il un moyen de récupérer les positions des caractères (de départ) dans une chaîne des résultats d'une correspondance regex () en Javascript?

stagas
la source

Réponses:

225

execrenvoie un objet avec une indexpropriété:

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

Et pour plusieurs matchs:

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

Gombo
la source
5
Merci de votre aide! Pouvez-vous me dire également comment trouver les index de plusieurs correspondances?
stagas
9
Remarque: utiliser le recomme variable et ajouter le gmodificateur sont tous deux cruciaux! Sinon, vous obtiendrez une boucle sans fin.
oriadam
1
@ OnurYıldırım - voici un jsfiddle qui fonctionne ... Je l'ai testé tout le chemin du retour à IE5 ... fonctionne très bien: jsfiddle.net/6uwn1vof
Jimbo Jonny
1
@JimboJonny, eh bien j'ai appris quelque chose de nouveau. Mon cas de test revient undefined. jsfiddle.net/6uwn1vof/2 qui n'est pas un exemple de recherche comme le vôtre.
Onur Yıldırım
1
@ OnurYıldırım - Retirez le gdrapeau et cela fonctionnera. Étant donné que matchc'est une fonction de la chaîne, pas de l'expression régulière, elle ne peut pas être avec état exec, donc elle ne la traite que comme exec(c'est-à-dire qu'elle a une propriété d'index) si vous ne recherchez pas une correspondance globale ... parce que l'état n'a pas d'importance .
Jimbo Jonny
60

Voici ce que j'ai trouvé:

// 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
la source
18
match.index + match[0].lengthfonctionne également pour la position finale.
Beni Cherniavsky-Paskin
vraiment sympa - comparaison gisted ici
Louis Maddox
1
@ BeniCherniavsky-Paskin, la position finale ne serait-elle pas match.index + match[0].length - 1?
David
1
@David, je voulais dire la position finale exclusive, prise par exemple par .slice()et .substring(). La fin inclusive serait de 1 de moins comme vous le dites. (Attention, inclusif signifie généralement l'index du dernier caractère à l'intérieur de la correspondance, à moins qu'il ne s'agisse d'une correspondance vide où il est 1 avant la correspondance et pourrait être -1entièrement en dehors de la chaîne pour une correspondance vide au début ...)
Beni Cherniavsky-Paskin
16

À partir de la documentation de developer.mozilla.org sur la .match()méthode String :

Le tableau retourné a une propriété d'entrée supplémentaire, qui contient la chaîne d'origine qui a été analysée. De plus, il possède une propriété index, qui représente l'index de base zéro de la correspondance dans la chaîne .

Lorsque vous traitez avec une regex non globale (c'est-à-dire pas de gdrapeau sur votre regex), la valeur renvoyée par .match()a une indexpropriété ... tout ce que vous avez à faire est d'y accéder.

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

Voici un exemple montrant que cela fonctionne également:

var str = 'my string here';

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

alert(index); // <- 10

J'ai testé cela avec succès depuis IE5.

Jimbo Jonny
la source
6

Vous pouvez utiliser la searchméthode de l' Stringobjet. Cela ne fonctionnera que pour le premier match, mais fera autrement ce que vous décrivez. Par exemple:

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

Voici une fonctionnalité intéressante que j'ai découverte récemment, j'ai essayé ceci sur la console et cela semble fonctionner:

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

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

Qui a renvoyé: "border 6 bottom 13 left 18 radius"

Donc, cela semble être ce que vous recherchez.

Felipeab
la source
6
attention simplement que les fonctions de remplacement ajoutent également des groupes de capture, alors notez que c'est toujours l' avant-dernière entrée de la fonction de remplacement argumentsqui est la position. Pas "le deuxième argument". Les arguments de la fonction sont "correspondance complète, groupe1, groupe2, ...., index de correspondance, chaîne complète mise en correspondance"
Mike 'Pomax' Kamermans
2

Dans les navigateurs modernes, vous pouvez accomplir cela avec string.matchAll () .

L'avantage de cette approche RegExp.exec()est qu'elle ne repose pas sur le fait que l'expression régulière soit avec état, comme dans la réponse de @ Gumbo .

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

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

brismuth
la source
1

Ce membre fn renvoie un tableau de positions basées sur 0, le cas échéant, du mot d'entrée à l'intérieur de l'objet 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 ;
}

Maintenant essaye

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

Vous pouvez également saisir des expressions régulières:

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

Ici, on obtient l'indice de position du terme linéaire.

Sandro Rosa
la source
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
la source
Ceci est une erreur. str.indexOfici trouve juste l'occurrence suivante du texte capturé par la correspondance, qui n'est pas nécessairement la correspondance. JS regex prend en charge les conditions sur le texte en dehors de la capture avec anticipation. Par exemple searchIndex("foobarfoobaz", "foo(?=baz)", true)devrait donner [6], non [0].
rakslice
pourquoi `[] .forEach.call (arr, function (element)` pourquoi pas arr.forEach ou arr.map
Ankit Kumar
-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

ou

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
la source