Повернути позиції регулярного вирівнювання () у Javascript?


154

Чи є спосіб отримати (початкові) позиції символів всередині рядка результатів збігу регулярних виразів () у Javascript?

Відповіді:


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
Спасибі за вашу допомогу! Чи можете ви мені також сказати, як я можу знайти індекси кількох збігів?
стага

9
Примітка: використання reзмінної та додавання gмодифікатора мають важливе значення! Інакше ви отримаєте нескінченну петлю.
oriadam

1
@ OnurYıldırım - ось ця функція jsfiddle про це працює ... Я перевірив це все до IE5 ... чудово працює: jsfiddle.net/6uwn1vof
Jonny

1
@JimboJonny, хм добре, я дізнався щось нове. Мій тестовий випадок повертається undefined. jsfiddle.net/6uwn1vof/2, який не є подібним до пошуку прикладом.
Onur Yıldırım

1
@ OnurYıldırım - Видаліть gпрапор і він запрацює. Оскільки matchце функція рядка, а не регулярний вираз, він не може бути подібним до стану exec, тому він лише трактує його як exec(тобто має властивість індексу), якщо ви не шукаєте глобальну відповідність ... тому що тоді стаціонарність не має значення .
Jimbo Jonny

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


18
match.index + match[0].lengthтакож працює для кінцевої позиції.
Бені Чернявський-Паскін


1
@ БеніЧернявський-Паскін, чи не була б кінцева позиція match.index + match[0].length - 1?
Девід

1
@David, я мав в виду виняткову кінцевої позиції, як і прийнято , наприклад , з допомогою .slice()і .substring(). Як ви говорите, інклюзивний кінець був би на 1 менше. (Будьте уважні, що інклюзивне зазвичай означає індекс останнього знаку всередині матчу, якщо тільки це порожній матч, де це 1 перед матчем і може бути -1поза рядком цілком для порожнього матчу на старті ...)
Бені Чернявський-Паскін

16

З Документів developer.mozilla.org про .match()метод String :

Повернений масив має додаткове властивість введення, яке містить початковий рядок, який був проаналізований. Крім того, він має властивість індексу, яка представляє нульовий індекс відповідності в рядку .

У роботі з неглобальним регулярним виразом (тобто жодним 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"

Тож, здається, це те, що ви шукаєте.


6
просто забувайте, що функції заміни додають також групи захоплення, тому зверніть увагу, що позиція завжди є другою за останнім записом у функції заміни arguments. Не "другий аргумент". Аргументи функції "повний матч, group1, group2, ...., індекс відповідності, повний рядок, протиставлений"
Майк '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);
});


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 regex підтримує умови для тексту поза захопленням з lookahead. Наприклад, searchIndex("foobarfoobaz", "foo(?=baz)", true)слід давати [6], ні [0].
rakslice

чому `[] .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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.