2010-06-23 1 views
1
<html><body><script> 
var matches = /(\w+)(\s*(\w+))?/.exec("aaa"); 
alert(matches.length); 
alert(typeof(matches[3])); 
</script></body><html> 

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

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

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

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

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

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

  • В Internet Explorer 6 соответствует [2] и соответствует [3] - пустая строка.

В принципе, как я должен проверить, если у меня есть «короткий» (например, «ааа») или «длинный» (например, «ааа БББ») выражение?

ответ

3

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

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

«А государство является упорядоченная пара (ENDINDEX, захватывает), где ENDINDEX целое и захватывает внутренний массив NCapturingParens значения. [.. .] N-ый элемент из захватывает - это либо строка, которая представляет значение, полученное n-м набором скобок-скобок, либо undefined, если n-й набор скобок скобок еще не достигнут."

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

9 ди Пусть г быть государственный результат вызова [[Match]] [...]

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

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

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

20. Для каждого целого я таким образом, что > 0 и I ≤ п

с. Let captureI be ith элемент rзахватывает массив.

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

21. Возврат A.

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

+0

Это было именно то, что я хотел видеть :) – GameZelda

3

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

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

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

+0

О 1-м вопросе, я ожидал, что у него будет 2 матча вместо 4. Но если он вернет совпадение для каждого типа скобок, это имеет смысл. Второй вопрос - настоящее сомнение. Поскольку я видел 2 разных поведения, я не знаю, что это должно быть, и я не видел его документально подтвержденным. if (matches [2]), похоже, работает в обоих, но я хотел бы увидеть некоторые документы для этого. Я не могу использовать String.split(), так как реальное регулярное выражение намного длиннее и сложнее, чем это. – GameZelda

+0

@GameZelda "", 0 и undefined - все ложные значения в JavaScript. Если вы боитесь такого поведения, проверьте оба условия. например 'if (тип совпадений [2] ===" undefined "|| matches [2] ===" ")' – nil

2

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

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

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

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

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

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

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