2016-03-06 5 views
0

У меня есть простой сценарий, соответствующий эпизод серии кодов, как s01e02 или s09e11. Идея состоит в том, чтобы найти все коды эпизодов в предоставленном тексте и создать массив объектов, содержащий все найденные эпизоды.Сочетание регулярных выражений «GI» модификаторов не работает для отдельных слов

Сначала я использовал match(), чтобы получить массив всех совпадающих кодов, затем прокручиваю коды, чтобы извлечь сезон и номер эпизода.

Проблема заключается в том, что при использовании одного и того же регулярного выражения с модификаторами /gi как для нахождения всех совпадений, так и для извлечения деталей эпизода я получаю сообщение об ошибке: Uncaught TypeError: Cannot read property '1' of null (см. Вывод консоли).

Случай 1 (отсутствие) - fiddle 1

var episodePatternGI = /s(\d{1,2})e(\d{1,2})/gi; 
var matches = 'S3E1 hehehe bla s09e12'.match(episodePatternGI); 
var episodes = []; 

matches.forEach(function(val) { 
    var ep = episodePatternGI.exec(val); 
    episodes.push({ 
    s: ep[1], 
    e: ep[2] 
    }); 
}); 

console.log(episodes); 

Случай 2 (рабочий) - fiddle 2

var episodePatternGI = /s(\d{1,2})e(\d{1,2})/gi; 
var matches = 'S3E1 hehehe bla s09e12'.match(episodePatternGI); 
var episodes = []; 

var episodePatternI = /s(\d{1,2})e(\d{1,2})/i; // g modifier removed 

matches.forEach(function(val) { 
    var ep = episodePatternI.exec(val); // New pattern applied 
    episodes.push({ 
    s: ep[1], 
    e: ep[2] 
    }); 
}); 

console.log(episodes); 

Как вы можете видеть, во втором case Я использую тот же шаблон, но модификатор g удален.

Почему не первый случай работает?

ответ

3

Проблема заключается в том, что lastIndex не сбрасывается автоматически, поэтому при вызове exec на второй матч, он не начнет искать в начале строки , и, следовательно, это не будет соответствовать.

Вы можете сбросить lastIndex вручную, установив его в 0:

var episodePatternGI = /s(\d{1,2})e(\d{1,2})/gi; 
var matches = 'S3E1 hehehe bla s09e12'.match(episodePatternGI); 
var episodes = matches.map(function(val) { 
    episodePatternGI.lastIndex = 0; 
    var ep = episodePatternGI.exec(val); 
    return { 
    s: ep[1], 
    e: ep[2] 
    }; 
}); 
console.log(episodes); 

не Calling exec несколько раз до достижения конца строки (а второй вызов должен быть достаточно), как показано на anubhava's answer, сбросит lastIndex слишком ,

+0

Точно ответ, который я искал. – lesssugar

+1

Все, что вы избили меня до ответа. Я как раз собирался отправить – 4castle

+2

Еще лучший ответ, хотя бы на самом деле * использовать * lastIndex' в ваших интересах и просто пропустить через 'exec()' до тех пор, пока он не вернет null. Поскольку в настоящее время регулярное выражение используется в два раза больше, чем должно быть. Пропустите часть массива совпадений. – 4castle

2

Вы должны использовать regexp.exec в цикле, чтобы захватить захваченную группу при использовании g флага:

var episodePatternGI = /s(\d{1,2})e(\d{1,2})/gi; 
var str = 'S3E1 hehehe bla s09e12'; 
var episodes = []; 

var m; 
while ((m = episodePatternGI.exec(str)) !== null) { 
    episodes.push({ 
     s: m[1], 
     e: m[2] 
     }); 
} 

console.log(episodes); 

Updated Fiddle

RegEx Demo (проверить генератор кода в этой ссылке)

+0

ОК, я вижу. В основном мне нужно вручную отслеживать индекс 'exec()' во время каждой итерации. Kinda раздражает;) Спасибо! – lesssugar

+0

То, что я не получаю, это то, что в моем коде я перебираю массив кодов, и я извлекаю сезон и эпизод из каждого кода ** отдельно **. Тем не менее, индекс 'exec()' как-то глобальный?Решение с 'while' немного отличается, более кратким. «ForEach» один - не работает - беспокоит меня. – lesssugar

+0

На самом деле, в этом случае это не обязательно, см. Обновленный ответ. – anubhava

0

Если вы хотите передать несколько флагов в RegExp в JS, вы также можете сделать что-то вроде этого:

var episodePatternGI = /s(\d{1,2})e(\d{1,2})/; 
var other = new RegExp(episodePatternGI.source, "gi"); 

здесь является актуальной темой: Changing the RegExp flags

Смежные вопросы