Теперь, когда вы знаете, как формируются регулярные выражения JavaScript, настало время разобраться, как их использовать. Мы выясним это в ходе обсуждения свойств и методов объектов RegExp и String, которые могут использоваться для проверки и анализа строк. Напомним, что регулярные выражения, созданные в предыдущей статье с помощью синтаксиса литералов, на самом деле являются объектами RegExp. В этом разделе мы отдадим предпочтение объектному синтаксису, чтобы вы смогли освоить оба варианта.
test()
Простейшим методом RegExp является test() — этот метод уже использовался во многих примерах выше. Возвращаемое методом логическое ц значение указывает, соответствует ли данная строка-аргумент регулярному выражению. Ниже определяется регулярное выражение, используемое затем для проверки двух строк:
1 2 3 |
var pattern = new RegExp("a*bbbc", "i"); // без учета регистра alert(pattern.test ("1а12с")); //покажет false alert(pattern.test("aaabBbcded")); //покажет true |
Подвыражения
Объект RegExp предлагает простой способ извлечения фрагментов строк, соответствующих части шаблона. Это достигается с помощью группирования тех частей шаблона (путем размещения вокруг них скобок), которые требуется извлечь. Предположим, нужно извлечь имена (но не фамилии) и телефонные номера из строк типа
1 |
Имя Фамилия NNN-NNNN |
где N обозначают цифры телефонного номера. Здесь можно использовать следующее регулярное выражение, в котором группируется часть, соответствующая имени, и часть, соответствующая телефонному номеру:
1 |
var pattern = /(\w+) \w+ ([\d-]{8})/; |
Этот шаблон можно прочитать так: один или больше символов, которые встречаются в словах, с последующим пробелом, затем еще один или больше символов, которые встречаются в словах, с последующим пробелом и, наконец, строка из восьми цифр и дефисов.
При сравнении строки с этим шаблоном скобки индуцируют подвыражения. Если сравнение оказывается успешным (т.е. обнаруживается совпадение), на эти указанные в скобках подвыражения можно ссылаться с помощью статических свойств $1 — $9 объекта класса RegExp. В продолжение нашего примера рассмотрим
1 2 3 |
var customer = "Alan Turing 555-1212"; var pattern = / (\w+) \w+ ([\d-]{8})/; pattern.test(customer); |
Поскольку шаблон содержит скобки, с помощью которых создаются два подвыражения (\w+ и [\d-] {8}), можно отдельно сослаться на соответствующие им две подстроки — «Alan» и «555-1212». Подстроки, доступные с помощью такого подхода, нумеруются слева направо, начиная с $ 1 и заканчивая обычно $ 9. Например, в результате выполнения фрагмента программного кода
1 2 3 4 |
var customer = "Alan Turing 555-1212"; var pattern = /(\w+) \w+ ([\d-]{8})/; if (pattern.test(customer)) alert("RegExp.$1 = " + RegExp.$1 + "\nRegExp.$2 = " + RegExp.$2); |
мы увидим :
RegExp.$1 = Alan
RegExp.$2 = 555-1212
Обратите внимание на то, что для доступа к компонентам-подвыражениям используется объект класса RegExp, а не созданный нами экземпляр RegExp или шаблон.
compile()
Метод compile() используется не слишком часто. Он заменяет существующее регулярное выражение новым. Этот метод предполагает те же аргументы, что и конструктор RegExp() (строка шаблона, и необязательные строки, содержащие флаги), и может использоваться для замены старого выражения новым:var pattern = new RegExp(«http:.* «,»i»);
1 2 3 |
// работа с этим регулярным выражением pattern.compile("https:.* ", "i"); // замена регулярного выражения новым |
Другой задачей использования этой функции является повышение эффективности. Регулярные выражения, объявляемые с помощью конструктора RegExp, компилируются (превращаются в подпрограммы проверки строк интерпретатором) при каждом их использовании, и это может занимать достаточно много времени, особенно в тех случаях, когда шаблон достаточно сложен. Явный вызов compile() избавляет от необходимости повторной компиляции, выполняя эту компиляцию заранее и только один раз.
ехес()
Объект RegExp предлагает также метод, называемый exec(). Этот метод используется, когда необходимо проверить, соответствует ли данная строка шаблону, и требуется дополнительная информация о соответствии, например, о начальной позиции в строке, где обнаружено соответствие. Можно также повторно обратиться к этому методу для той же строки, чтобы двигаться по соответствиям дальше и дальше.
Метод exec() принимает в качестве аргумента строку для проверки и может вызываться в кратком виде с помощью непосредственного вызова имени регулярного выражения как функции. Например, два вызова в следующем примере эквивалентны:
1 2 3 |
var pattern = /http:.*/; pattern.exec("http://www.w3c.org/"); pattern(^http://www.w3c.org/"); |
Метод exec() возвращает массив с множеством свойств. Среди них length (указывает длину массива), input (содержит оригинальную входную строку), index (содержит позицию символа, с которой в строке начинается соответствие) и lastlndex (указывает позицию, где соответствие заканчивается, т.е. где будет начинаться следующий поиск). Следующий сценарий иллюстрирует использование метода exec() и возвращаемых им значений:
1 2 3 4 5 6 7 |
var pattern = /кот/; var result = pattern.exec("Это был кот, жирный кот по кличке Руфус."); document.writeln("result = "+result+"<br />"); document.writeln("result.length = "+result.length+"<br />"); document.writeln("result.index = "+result.index+"<br />"); document.writeln("result.lastlndex = "+result.lastlndex+"<br />"); document.writeln("result.input = "+result.input+"<br />"); |
Результат выполнения этого фрагмента программного кода будет таким:
result = кот
result.length = 1
result.index = 8
result.lastlndex = 11
result.input = Это был кот, жирный кот по кличке Руфус.
Возвращаемый массив может содержать более одного элемента, если используются подвыражения. Например, в следующем сценарии используются три заключенные в скобки подвыражения, которые анализируются в массиве отдельно:
1 2 3 4 5 6 7 8 |
var pattern = /(кот) (и) (пес) /; var result = pattern.exec("Мои кот и пес оба черные."); document.writeln("result = "tresult); document.writeln("result.length = "tresult.length); document.writeln("result.index = "+result.index); document.writeln("result.lastlndex = "+result.lastlndex); document.writeln("result.input = "+result.input); |
Результат выполнения этого фрагмента программного кода будет таким:
result = кот и пес ,кот,и,пес
result.length = 4
result.index = 4
result.lastlndex = 14
result.input = Мои кот и пес оба черные.
метод exec() размещает всю соответствующую строку в нулевом элементе массива, а подстроки, соответствующие заключенным в скобки подвыражениям, — в последующих элементах.
ехес() и флаг глобальности
Иногда требуется найти не только первое соответствие шаблону в строке, а все соответствия. Добавление флага глобальности (g) к регулярному выражению указывает на необходимость искать все совпадения, а не только первое (т.е. искать глобально).
Интерпретация флага глобальности объектами RegExp и String довольно хитроумна. В RegExp он используется для выполнения глобального поиска пошагово, т.е. с помощью анализа каждого последующего совпадения с шаблоном по очереди. В String флаг глобальности используется для выполнения глобального поиска сразу, т.е. с помощью анализа всех совпадений с шаблоном в одном обращении к функции. Использование флага глобальности в методах String мы рассмотрим в следующем разделе.
Чтобы продемонстрировать разницу между регулярными выражениями с флагом глобальности и без него, рассмотрим следующий простой пример:
1 2 3 4 5 6 7 8 9 10 |
var lucky = "Счастливыми числами являются 3, 14 и 27"; var pattern = /\d+/; document.writeln("Без флага глобальности получаем:"); document.writeln(pattern.exec(lucky) ) ; document.writeln(pattern.exec(lucky)); document.writeln(pattern.exec(lucky)); pattern = /\d+/g; document.writeln("С флагом глобальности получаем:"); document.writeln(pattern.exec(lucky)) ; document.writeln(pattern.exec(lucky)); document.writeln(pattern.exec(lucky) ); |
Как видно результата при наличии флага глобальности exec() начинает поиск с позиции, следующей за найденным соответствием. Без флага глобальности exec() всегда возвращает первую найденную часть строки.
Результат выполнения этого фрагмента программного кода будет таким:
Без флага глобальности получаем:
3
3
3
С флагом глобальности получаем:
3
14
27
Как выполняется глобальный поиск? Напомним, что exec() устанавливает свойство lastlndex как в возвращаемом массиве, так и в объекте класса RegExp, в результате чего указатель соответствует символу, следующему непосредственно за подстрокой, которая только что была найдена. При последующих вызовах метода exec() поиск в строке будет начинаться с позиции, указанной свойством lastlndex. Если соответствия не найдено, значение lastlndex устанавливается равным нулю.
При типичном использовании exec() выполняется цикл по всем подстрокам, соответствующим регулярному выражению, с получением полной информации о каждом совпадении. Примером такого использования является следующий фрагмент программного кода, в котором находятся слова в заданной строке. Результат (при условии заключения указанного программного кода в рамки дескриптора <рге>) показан ниже. Обратите внимание на то, как в соответствии с вышеприведенным обсуждением меняются значения lastlndex.
1 2 3 4 5 6 7 8 9 10 11 |
var sentence = "Ну очень интересное предложение."; var pattern = /\В[а-яА-Я0-9_]+\B/g; // распознает слова, глобально var token = pattern.exec(sentence); // поиск первого соответствия while (token != null) { // если соответствие найдено, выводится информация о нем document.writeln("Найдено " + token[0] + " "); document.writeln("\ttoken.input = " + token.input); document.writeln("\ttoken.input = " + token.index); document.writeln("\ttoken.lastlndex = " + token.lastlndex + "\n "); token = pattern.exec(sentence); // поиск следующего соответствия } |
Результат выполнения этого фрагмента программного кода будет таким:
Найдено Ну
token.input = Ну очень интересное предложение.
token.index = 0
token.lastlndex = 2
Найдено очень
token.input = Ну очень интересное предложение.
token.index = 3
token.index = 8
Найдено интересное
token.input = Ну очень интересное предложение.
token.index = 9
token.lastlndex = 19
Найдено предложение
token.input = Ну очень интересное предложение.
token.index = 20
token.lastlndex = 31
Есть одно предостережение, касающееся использования метода exec(). Если поиск прекращается до последнего соответствия, необходимо вручную установить нулевое значение для свойства lastlndex регулярного выражения. Если этого не сделать, в следующий раз, когда придется использовать это регулярное выражение, поиск автоматически начнется с позиции lastlndex, а не с начала строки.
Свойства RegExp
Использование внутренних свойств экземпляра объектов регулярных выражений и статических свойств (свойств класса) объекта RegExp может оказаться полезным как при решении сложных задач соответствия, так и при отладке. Свойства экземпляра объектов RegExp приводятся в табл.; почти все они уже известны читателю.
Свойство | Значение | Пример |
global | Логическое значение, указывающее, установлен ли флаг глобальности (g). Доступно только для чтения | var pattern = /(кот)-(пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln (pattern.global); // печатает true |
ignoreCase | Логическое значение, указывающее, установлен ли флаг независимости от регистра (i). Доступно только для чтения | var pattern = / (кот) — (пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln(pattern.ignoreCase); // печатает false |
lastlndex | Целое значение, указывающее позицию в строке, с которой будет начинаться следующий поиск. Это значение можно менять | var pattern = /(кот)-(пес)/g; pattern.test («это кот-пес и кот-пес»); document.writeln(pattern.lastlndex); // печатает 11 |
multiline | Логическое значение, указывающее, установлен ли флаг многострочности (m). Доступно только для чтения | var pattern = /(кот)-(пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln(pattern.multiline); // печатает false |
source | Строковая форма регулярного выражения. Доступно только для чтения | var pattern = /(кот)-(пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln(pattern.source); // печатает (кот)-(пес) |
Объект класса RegExp имеет статические свойства, которые также могут оказаться весьма полезными. Эти свойства приведены в табл. Они могут иметь две формы. Для альтернативной формы используется знак доллара и специальный символ — эта форма знакома тем, кто уже активно работал с регулярными выражениями. Недостатком альтернативной формы является то, что доступ к ней осуществляется в режиме ассоциативного массива. Заметим, что использование этой формы, вероятно, смутит тех, кто не работал с языками типа Perl, поэтому, пожалуй, лучше ее не использовать.
Свойство | Альтернативная форма | Значение | Пример |
$1,$2…..$9 | Нет | Строки, соответствующие первым девяти подвыражениям в скобках для последнего найденного соответствия шаблону | var pattern = /(кот)-(пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln(«$l=»+RegExp.$1); document.writeln («$2=»+RegExp.$2) ; // печатает $1= кот $2 = пес |
index | Нет | Значение индекса первого символа в строке, с которого начинается соответствие шаблону, найденное в результате последней операции сравнения. Это свойство имеет широкую поддержку, но не является частью стандарта ЕСМА, поэтому данное значение лучше вычислить с помощью свойства length найденной подстроки и lastlndex | var pattern =/(кот)-(пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln(RegExp.index); // печатает 4 |
input | $_ | Строка, используемая для сравнения с данным шаблоном по умолчанию | var pattern = / (кот)-(пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln (RegExp.input); // печатает «это кот-пес и кот-пес» document.writeln(RegExp[‘$_’]); // печатает «это кот-пес и кот-пес» |
lastlndex | Нет | Целочисленное значение, указывающее позицию в строке, с которой будет начинаться следующий поиск. Соответствует значению аналогичного свойства экземпляра, которое использовать предпочтительнее | var pattern = / (кот)-(пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln(RegExp.lastlndex); // печатает 11 |
lastMatch | $& | Строка с соответствующим шаблону текстом, найденным в результате последней операции сравнения | var pattern = /(кот)-(пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln(RegExp.lastMatch); // печатает «кот-пес» document.writeln(RegExp[‘$&’]); // печатает «кот-пес» |
lastParen | $+ | Строка, соответствующая последнему заключенному в скобки подвыражению для последнего найденного соответствия шаблону | var pattern = /(кот)-(пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln(RegExp.lastParen); // печатает «пес» document.writeln(RegExp[‘$+’]); // печатает «пес» |
leftContext | $` | Строка с текстом, размещенным слева от по- . следнего найденного соответствия шаблону | var pattern = /(кот)-(пес)/g; pattern.test(«это кот-пес и кот-пес»); document.writeln(RegExp.leftContext); // печатает «это» document.writeln(RegExp[‘$`’]); // печатает «это» |
rightContext | $’ | Строка с текстом, размещенным справа от последнего найденного соответствия шаблону | var pattern = /(кот)-(пес)/g; pattern.test («это кот-пес и кот-пес»); document.writeln(RegExp.rightContext); // печатает «и кот-пес» document.writeln(RegExp[‘$\’ ‘]) ; // печатает «и кот-пес» |
Интересным аспектом статических свойств класса RegExp является то, что они являются глобальными и, таким образом, изменяются каждый раз, когда вы используете регулярное выражение, как с методами String, так и с методами RegExp. По этой причине они являются исключением из правила, предусматривающего для JavaScript статический обзор данных. Для указанных свойств используется динамический обзор — т.е. изменения отражаются в объекте RegExp в контексте функции вызова, а не в контексте объемлющего исходного кода. Например, если в некотором фрейме вызывается функция, использующая регулярные выражения в другом фрейме, то JavaScript обновит статические свойства RegExp во фрейме вызова, а не во фрейме, где находится вызываемая функция. Это редко создает проблемы, но об этом необходимо помнить, когда статические свойства приходится использовать в окружении с фреймами.