Вернуть позиции регулярного выражения match () в Javascript?

154

Есть ли способ получить (начальные) позиции символов внутри строки результатов регулярного выражения match () в Javascript?

stagas
источник

Ответы:

225

execвозвращает объект со indexсвойством:

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

И для нескольких матчей:

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

гумбо
источник
5
Спасибо за вашу помощь! Можете ли вы также сказать мне, как я могу найти индексы нескольких совпадений?
Stagas
9
Примечание: использование в reкачестве переменной и добавление gмодификатора имеют решающее значение! В противном случае вы получите бесконечный цикл.
Ориадам
1
@ OnurYıldırım - вот jsfiddle из этого работает ... Я проверил все это до IE5 ... прекрасно работает: jsfiddle.net/6uwn1vof
Джимбо Джонни
1
@JimboJonny, я хорошо узнал что-то новое. Мой тестовый случай возвращается undefined. jsfiddle.net/6uwn1vof/2, который не похож на ваш пример поиска.
Онур Йылдырым
1
@ OnurYıldırım - Уберите gфлаг, и он будет работать. Поскольку matchэто функция строки, а не регулярное выражение, она не может быть похожей на состояние exec, поэтому она обрабатывает ее как exec(т.е. имеет свойство index), если вы не ищете глобального соответствия ... потому что тогда состояние не имеет значения ,
Джимбо Джонни
60

Вот что я придумал:

// 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
источник
18
match.index + match[0].lengthтакже работает для конечной позиции.
Бени Чернявский-Паскин
действительно хорошо - сравнение состоялось здесь
Луи Мэддокс
1
@ BeniCherniavsky-Paskin, не будет ли конечная позиция match.index + match[0].length - 1?
Дэвид
1
@ Давид, я имел в виду исключительную конечную позицию, как, например, .slice()и .substring(). Инклюзивный конец будет на 1 меньше, как вы говорите. (Будьте осторожны, инклюзивный обычно означает индекс последнего символа в матче, если только это не пустое совпадение, где он равен 1 перед матчем и может находиться -1вне строки целиком для пустого совпадения в начале ...)
Бени Чернявский-Паскин
16

Из документации developer.mozilla.org о .match()методе String :

Возвращаемый массив имеет дополнительное входное свойство, которое содержит исходную строку, которая была проанализирована. Кроме того, у него есть свойство index, которое представляет нулевой индекс совпадения в строке .

При работе с неглобальным регулярным выражением (т. Е. Без gфлага на вашем регулярном выражении) возвращаемое значение .match()имеет indexсвойство ... все, что вам нужно сделать - это получить к нему доступ.

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

Вот пример, показывающий, как это работает:

var str = 'my string here';

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

alert(index); // <- 10

Я успешно проверил это вплоть до IE5.

Джимбо Джонни
источник
6

Вы можете использовать searchметод Stringобъекта. Это будет работать только для первого матча, но в противном случае будет делать то, что вы описываете. Например:

"How are you?".search(/are/);
// 4
Джимми Куадра
источник
6

Вот интересная особенность, которую я обнаружил недавно, я попробовал это на консоли, и она, кажется, работает:

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

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

Что вернуло: "граница 6, нижний 13, левый 18 радиус"

Так что это, кажется, то, что вы ищете.

felipeab
источник
6
просто имейте в виду, что функции замены также добавляют группы захвата, поэтому обратите внимание, что это всегда вторая позиция в функции замены, argumentsкоторая является позицией. Не «второй аргумент». Аргументы функции: «полное совпадение, group1, group2, ...., индекс совпадения, сопоставление полной строки»
Mike 'Pomax' Kamermans
2

В современных браузерах вы можете сделать это с помощью string.matchAll () .

Преимущество этого подхода по сравнению с тем RegExp.exec(), что он не основан на регулярном выражении, как в ответе @ Gumbo .

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

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

brismuth
источник
1

Этот член fn возвращает массив позиций на основе 0, если таковые имеются, входного слова внутри объекта 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 ;
}

Сейчас попробуй

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

Вы также можете ввести регулярные выражения:

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

Здесь можно получить индекс положения линейного члена.

Сандро Роза
источник
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));
Ярослав
источник
Это неверно str.indexOfздесь просто находит следующее вхождение текста, захваченного совпадением, которое не обязательно совпадает. JS регулярное выражение поддерживает условия для текста за пределами захвата с предвидением. Например searchIndex("foobarfoobaz", "foo(?=baz)", true)должен дать [6], а не [0].
Ракслице
почему `[] .forEach.call (arr, function (element)` почему нет arr.forEach или 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

или

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
источник