Вопросительный знак в регулярных выражениях в Javascript (странное поведение) - PullRequest
1 голос
/ 23 июня 2010
<html><body><script>
var matches = /(\w+)(\s*(\w+))?/.exec("aaa");
alert(matches.length);
alert(typeof(matches[3]));
</script></body><html>

Я действительно новичок в регулярных выражениях, так что это может быть очень простой вопрос.

Регулярное выражение выше /(\w+)(\s*(\w+))?/ соответствует шаблонам типа «aaa», «123», «my_var» или «aaa bbb», «123 456», «my_var my_value».

Для выражения типа «aaa bbb» соответствует = ["aaa bbb", "aaa", " bbb", "bbb"], но для выражения типа «aaa» соответствует = ["aaa", "aaa", ???, ???]

Первое, что меня удивило, это то, что match.length = 4. Я ожидал, что это будет 2, но я не вижу ни одного документа, объясняющего, каким он должен быть. Как это работает?

И второе, что меня удивило, это то, что два «лишних» совпадения, которые я получил, работают по-разному в двух браузерах, в которых я проверял это:

  • В Firefox 3.6.3 совпадения [2] и совпадения [3] не определены.

  • В Internet Explorer 6 совпадения [2] и совпадения [3] являются пустой строкой.

В общем, как мне проверить, есть ли у меня выражение "short" (например, "aaa") или "long" (например, "aaa bbb")?

Ответы [ 3 ]

3 голосов
/ 23 июня 2010

Стандарт ( ECMAScript 5 ) довольно понятен.Длина должна быть 4, и IE неправильный (шокирует, я знаю).

Из §15.10.2.1, « NcapturingParens - это общее количество оставленных скобок для захвата».У вас есть 3.

"A State - упорядоченная пара ( endIndex , захватывает ), где endIndex - этоцелое число и захватывает является внутренним массивом значений NcapturingParens . [...] n-й элемент захватывает является либо строкой, представляющей значение, полученноеn-й набор скобок захвата или undefined , если n-й набор скобок захвата еще не достигнут. "

§15.10.6.2, который описывает exec, говорит:

9.di Пусть r будет State результатом вызова [[Match]].[...]

12.Пусть n будет длиной r s захватывает массив.(Это то же значение, что и 15.10.2.1 NCapturingParens .)

13.Пусть A будет новым массивом, созданным как будто выражением new Array () [...]

17.Вызвать внутренний метод [[DefineOwnProperty]] для A с аргументами "length", дескриптором свойства {[[Value]]: I + 1} и true.[...]

20.Для каждого целого числа i такого, что I> 0 и I ≤ n

a.Пусть captureI будет ith элементом r s захватывает массив.

b.Вызвать внутренний метод [[DefineOwnProperty]] для A с аргументами ToString ( i ), дескриптор свойства {[[Value]]: captureI , [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и true.

21.Возврат A .

Таким образом, длина должна быть 4 (3 + 1), а захваты, которые не достигнуты (например, (\s*(\w+)) в вашем шаблоне), остаются неопределенными,К счастью, undefined и "" (пустая строка) являются ложными.Это означает, что они ложны, когда рассматриваются как логическое значение.Таким образом, вы можете обойти ошибку IE, выполнив if(matches[2])

3 голосов
/ 23 июня 2010

Массив matches содержит два вида совпадений, всю совпавшую строку и ваши объединенные шаблоны.Таким образом, в этом случае у него есть четыре элемента: общая совпавшая строка, "aaa", первый суб-результат, снова "aaa", и оба (\s*(\w+)) и (\w+) имеют пустые совпадения.

Разница междуFirefox и IE тривиальны.

Ответ на вопрос о том, как вы должны проверять результаты матчей, прост: просто проверьте значения matches[1] и matches[3], посмотрите, не определены они или нет.Если ваши строки для синтаксического анализа все в порядке \w+\s*\w+, просто String.split() они будут в порядке.Результирующий массив будет коротким, если ваша строка короткая, и длинным, если ваша строка будет "aaaa bbbb".Будьте осторожны с такими случаями, как "aaa ".

2 голосов
/ 23 июня 2010

Попробуйте это с этими двумя регулярными выражениями:

var m1 = /(\w+)(\s*)/.exec("aaa");   // ["aaa", "aaa", ""]
var m2 = /(\w+)(\s+)?/.exec("aaa");  // ["aaa", "aaa", undef]

В первом случае группа № 2 не потребляет никаких символов, но * означает, что совпадение нулевой длины в порядке;говорят, что в этой группе ничего не найдено , т. е. пустая строка.Во втором случае (\s+) завершается неудачно, но общее совпадение успешно, потому что сама группа была необязательной.Результат undef означает, что группа не участвовала в матче .

Вот как это должно работать: пустая строка означает, что группа участвовала в матче, но не использовалалюбые персонажи;undef означает, что он не участвовал в матче.Возвращая пустую строку для не участвующих групп, Internet Explorer стирает различие между группой, которая ничего не соответствует, и группой, которая не совпадает.

Однако ситуация намного хуже, чем в IE.не единственный плохой парень;см. этот пост в блоге для подробностей.

Но есть одна вещь, с которой согласны все браузеры: количество элементов в массиве match контролируется количеством групп захвата врегулярное выражение, независимо от того, участвуют они в матче или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...