Поиск Google Внутренний поиск Библиотека бесплатного софта

Регулярные выражения RegExp в JavaScript

Сегодня практически каждый программист должен знать, что такое регулярные выражения (RegExp, RegEx). Их использование позволяет сократить громоздкий и трудночитаемый код до нескольких строчек.

 

Что такое регулярные выражения (RegExp) в JavaScriptК оглавлению

Регулярные выражения используются для поиска подстрок текста по заданному шаблону (маске), состоящего из символов и метасимволов. Эта технология получила свою популярность после включения её в состав стандартных утилит Unix-систем, что привело к прорыву в электронной обработке текстов.

Давайте познакомимся с регулярными выражениями на примере. Допустим, у нас есть какая-то строка.

var str = "Кошка покормила своих котят";

//Создадим маску поиска
var pattern = /ко./;

//Теперь произведем поиск по указанной маске
var result = pattern.exec(str); 
document.write(result);

//В результате мы увидим "кор"

В переменной pattern мы указали маску в виде /кo./. Это как обычная строка, только заключена не в кавычки, а в символы "/".

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

В итоге скрипт нашел в строке первое совпадение с шаблоном. Тогда возникает вопрос - а почему же результатом не будет строчка "Кош"? Все просто, шаблон поиска чувствителен к регистру букв, а значит "Кош" и "кош" будут разными строками. А та маска, которую мы создали, подходит только для второго случая... Чтоб скрипт игнорировал регистр символов, надо добавить специальный атрибут (ignoreCase) к маске:

var pattern = /ко./i;

Теперь поиск будет осуществляться без учета регистра символов, и после выполнения скрипта мы увидим "Кош". Стоп, ведь мы нашли только первое вхождение данной подстроки, как нам найти все подстроки подходящие под шаблон поиска?

Все просто, нужно добавить еще один атрибут (global) к маске поиска и тогда мы сможем вызывать методе exec множество раз для поиска дальнейших совпадений. Причем индекс найденной подстроки будет находиться в переменной index:

var pattern = /ко./gi;
var result = '';

while((find = pattern.exec(str)) != null) {
  result += find + " - начинается с " + find.index + "-го символа<br/>";
  result += "Дальше поиск начнется с " + pattern.lastIndex + "-го символа<br/><br/>";
}
document.write(result);

Теперь в браузере мы увидим такой результат:

Кош - начинается с 0-го символа
Дальше поиск начнется с 3-го символа

кор - начинается с 8-го символа
Дальше поиск начнется с 11-го символа

кот - начинается с 22-го символа
Дальше поиск начнется с 25-го символа

Маску поиска и её параметры можно также указывать через конструктор объекта RegExp:

var pattern = new RegExp("ко.","gi");

Представление символов и метасимволовК оглавлению

Основная часть символов представляют сами себя в маске поиске за исключением ()[]\^$|?+. Чтобы отобразить их в виде строковых символов необходимо заэкранировать их слешем: "\." - точка, "\?" - знак вопроса, "\\" - левый слеш, и тд...

Кроме этого существуют еще набор метасимволов, которые набираются со слешем, вот они:

СимволЗначение
\wЭтот метасивол показывает, что вместо него может стоять любой латинский символ словаря, включая буквы, цифры и знак подчеркивания. То есть, шаблон /\wat/ означает "bat", "rat", "0at", "_at" и тд.
\WА это будет полной противоположностью предыдущего метатега. Он задает шаблон поиска несловарных (латинских) символов. /\Wat/ будет "$at", "?at"...
\d Обозначает любой цифровой символ. /\dat/: "5at", "2at"...
\D Любой НЕцифровой символ. /\Dat/: "rat", "cat"...
\s Обозначает пробелы, табуляцию, перевод строки и другие юникодные пробельные символы.
\S Все НЕпробельные символы.
\n,\r,\f Соответствует спецсимволам перевод строки, line-feed и form-feed соответственно.
\t,\v Задают символ горизонтальной и вертикальной табуляции.
\xhh Задает символ с кодом hh (2 шестнадцатеричные цифры).
\uhhhh Найдет символ с кодом hhhh (4 шестнадцатеричных цифры).

Наборы символов (символьные классы)К оглавлению

С помощью квадратных скобок [] можно перечислить те символы, которые могут находиться в маске поиске. Например, f[a4_]s дает знать интерпретатору, что слово может иметь такие представления: fas, f4s или f_s.

Также можно через дефис указать диапазон символов, которые могут там стоять. [a-z123@] - все буквы латинского алфавита или цыфры 1,2,3 или собачка.

Если необходимо исключить какой-то символ, то перед ним ставится "^": [^a-z] - означает любой символ кроме букв латинского алфавита...

Мы уже использовали его ранее, но хочу еще раз напомнить, что метасимвол точка "." задает любой возможный символ. Его можно использовать без квадратных скобок.

Позиционирование маски поискаК оглавлению

Замечательной особенностью является возможность указать в каком месте слова или строки находится интересуемый нас шаблон. Указав "cat$" мы сможем найти слово cat, которое находится в самом конце строки. С Вашего позволения я скопирую сюда довольно подробную и интересную таблицу с википедии:

МетасимволПозиционированиеПримерСоответствие
^ Начало строки ^b bbb bbb
$ Конец строки b$ bbb bbb
\b Граница слова b\b bbb bbb
\bb bbb bbb
\B Не граница слова \Bb\B bbb bbb

Поиск последовательностей (квантификация)К оглавлению

С помощью скобок {} можно задавать сколько раз будет повторяться символ стоящий перед ним (в том числе класс или группа). Приведенная ниже таблица поможет Вам разобраться с синтаксисом:

ПредставлениеЧисло повторенийПримерСоответствие
{n} Ровно n ca{3}t caaat
{m,n} От m до n включительно ca{2,4}t caat, caaat, caaaat
{m,} Не менее m ca{2,}t caat, caaat, caaaat и т.д.
{,n} Не более n ca{,3}t ct, cat, caat, caaat

Полный синтаксис используют довольно редко, когда нужно сделать сложную маску. На практике в основном используют краткую запись квантификаторов:

ПредставлениеЧисло повторенийЭквивалентПримерСоответствие
* Ноль или более {0,} ca*t ct, cat, caat, caaat и т.д.
+ Одно или более {1,} ca+t cat, caat и т.д. (но не ct)
? Ноль или одно {0,1} ca?t ct или cat

Очень часто используют комбинацию ".*", что означает любую последовательность символов между тем, что стоит слева и справа в маске.

Если символы {} не образуют квантификатор, то их особое значение игнорируется, и они считаются обычными символами.

Ленивая и жадная квантификацииК оглавлению

Жадность - это стремление интерпретатора захватить максимально длинную строку, которая соответствует шаблону. Например, у нас есть строка:

z = 2 * (x + y) * (x - y)

Если мы хотим получить выражение в первых скобках, то попробуем задать вот такую маску: /\(.*\)/. Результат будет таким:

(x + y) * (x - y)

Обуздать жадность интерпретатора можно двумя способами:

1. В маске запретить двигаться дальше одной закрывающей скобки - /\([^\)]*\)/.

2. Воспользоваться ленивым квантификатором, добавив знак вопроса после звездочки - /\(.*?\)/.

После чего результат будет таким как мы и хотели:

(x + y)

Однако надо быть осторожным. Использование ленивых квантификаторов может повлечь за собой обратную проблему, когда найденному результату соответствует слишком короткая строка (в частности пустая).

ЖадныйЛенивый
* *?
+ +?
{n,} {n,}?

К сожалению, алгоритм поиск последовательностей в регулярных выражениях очень громоздкий - он имеет рекурсивный вид. Чтобы избежать ненужных итераций обычно используют ревнивые квантификаторы (сверхжадные). Но JavaScript, почему-то, их не поддерживает.

ГруппировкаК оглавлению

Заключив некоторую последовательность в "(?:шаблон)" мы сможем применять к ней квантификаторы. Например, /(?:пр[ау]м-?)*/ найдет строку:

прам-прам-прумпрам-прум-прампрум

Также довольно полезным является оператор перечисления - "|". Указав шаблон /сra(?:ck|sty)/, интерпретатор сначала попробует найти "crack", а потом "crasty". Главное не забыть, что порядок указывается слева на право...

В регулярных выражениях также можно использовать комментарии в виде /ab(?#комментарий)c/, но JavaScript НЕ поддерживает эту возможность.

Обратная связьК оглавлению

Обратная связь позволяет запоминать отдельные подшаблоны в массиве для дальнейшего их использования. Для поиска с обратной связью нужно заключить подшаблон в круглые скобки ().

К примеру, воспользуемся таким шаблоном /c(a)t/. В результате поиска интерпретатор вернет массив с элементами cat и a (нумерация с нуля). В нулевой ячейке хранится результат поиска, а в первой - найденный в скобках подшаблон.

Массив формируется по порядку первого нахождения во время поиска. А значит, мы можем обращаться к этому массиву при задании шаблона. Значения массива получаем с помощью метасимволов от \1 до \9.

Маска /(пум|пам)-\1/ найдет строчку "пум-пум" или "пам-пам". Но не "пум-пам" и не "пам-пум"!

Просмотр вперед и назадК оглавлению

В возвращаемый результат можно не включать ненужные условия поиска, но только если они стоят перед или после искомой строки. Чтобы разобраться, давай посмотрим такую таблицу:

ПредставлениеПросмотрПримерСоответствие
(?=шаблон) Вперёд Петр(?=I) Петр, ПетрI, ПетрII
(?!шаблон) Вперёд с отрицанием Петр(?!I) Петр, ПетрI, ПетрII
(?<=шаблон) Назад (?<=Петр)I Петр, ПетрI, ПетрII
(?<!шаблон) Назад с отрицанием (?<!Петр)I Петр, ПетрI, I

Использование регулярных выражений (RegExp) JavaScriptК оглавлению

Сейчас, когда необходимый шаблон уже присвоен объекту RegExp, что же с ним делать дальше? Существует два пути применения регулярных выражений. Первый заключается в использовании объекта RegExp, а второй - в использовании методов объекта String.

Ниже представлены методы объекта RegExp, которые обеспечивают поиск по шаблону. Обратите внимание, эти методы требуют передачи в качестве аргумента объекта String, в котором выполняется поиск.

МетодОписание
RegExp.exec(str) Осуществляет поиск по заданному шаблону в строке str и возвращает результат.
RegExp.test(str) Осуществляет поиск по заданному шаблону в строке str и возвращает true, если совпадение найдено и false - в противном случае.

В следующей таблице показаны методы объекта String, которые позволяют выполнить поиск по шаблону. Все они требуют передачи в качестве параметра объект RegExp, в котором осуществляется поиск.

МетодОписание
String.search(regExpObj,str) Возвращает позицию вхождения шаблона regExpObj внутри строки.
String.match(regExpObj) Осуществляет поиск шаблона regExpObj внутри строки и возвращает результат.
String.replace(regExpObj,str) Заменяет все вхождения шаблона regExpObj на str.

Метод RegExp.test( String )

Используется для проверки существования строки указанной в шаблоне. Например:

if ( /\s/.test('Это простая строка') ) {
	alert('В строке есть пробелы');
}

Метод RegExp.exec( String )

Он возвращает массив и выставляет свойства регулярного выражения, по которому осуществлялся поиск. Если совпадение не найдено, то он возвращает null.

Например,

//Найти одну c, за которой следует 1 или более a, за которыми одна c
//Запомнить найденные a и следующую за ними c
//Регистронезависимый поиск
var pattern = /c(a+)(c)/ig;
var result = pattern.exec("ncaAcasaz");

В результате работы этого скрипта будут такие результаты:

ОбъектСвойство/ИндексОписаниеПример
result   Содержимое result ["caAc", "aA", "c"]
index Индекс совпадения (от 0) 1
input Исходная строка. ncaAcasaz
[0] Последние совпавшие символы caAc
[1], ...[n] Совпадения во вложенных скобках, если есть. Число вложенных скобок не ограничено. [1] = aA
[2] = c
pattern lastIndex Индекс, с которого начинать следующий поиск. 5
ignoreCase Показывает, что был включен регистронезависимый поиск, флаг "i". true
global Показывает, что был включен флаг "g" поиска всех совпадений. true
multiline Показывает, был ли включен флаг многострочного поиска "m". false
source Текст паттерна. c(a+)(c)

Метод String.search( RegExpObj )

Осуществляет поиск регулярного выражения в строке и возвращает его индекс ( аналог RegExp.test() ).

if ( 'Это простая строка'.search(/\s/) ) {
  alert('В строке есть пробелы');
}

Метод String.match( RegExpObj )

Если в маске поиска нет флага g, то этот метод возвращает тот же результат что и RegExp.exec().

Если же флаг присутствует в шаблоне, то возвращает массив со всеми совпадениями.

var str = "Кошка покормила своих котят";
alert(str.match(/ко./gi))

Функция вернет массив "Кош,кор,кот".


Метод String.replace( RegExpObj, String )

Это одна из самых интересных функций, в которой можно использовать регулярные выражения. Функция не меняет строку, к которой применяется, а просто возвращает результат. Она имеет два параметра:

var newStr = str.replace(SubStr,newSubStr);

Это одна из стандартных функций объекта String. И, к счастью, можно вместо обычных строк использовать регулярные выражения. Вторым параметром можно передавать даже функцию.

var str = "Кошка покормила своих котят";
str = str.replace(/ко./,'0')
alert(str);

В результате мы получим такую строку "Кошка по0мила своих котят".

Чтобы заменились все совпадения в строке, нужно добавить еще параметр global к шаблону поиска:

alert( 'Запятые, и. точки. тут, вовсе. не, нужны'.replace(/[,.]/g, '') );

Кроме этого функция позволяет использовать параметры, которые возвращаются в результате поиска с обратной связью.

var re = /(\w+)\s(\w+)/;
var str = "Александр Пушки";
document.write(str.replace(re, "$2, $1"))

Этот сценарий выведет текст: "Пушкин, Александр". Ниже привожу таблицу метасимволов, которые можно использовать в строке замены:

МетасимволОписание
$$ Вставляет "$".
$& Вставляет найденную подстроку.
$` Вставляет часть строки, которая предшествует найденному вхождению.
$' Вставляет часть строки, которая идет после найденного вхождения.
$n or $nn Где n или nn - десятичные цифры, вставляет подстроку вхождения, запомненную n-й вложенной скобкой, если первый аргумент - объект RegExp.

ДополнительноК оглавлению

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

Более подробно они описаны в книге (англ.) Beginning Regular Expressions.

Комментарии 

 
+5 #1 John 29.10.2010 09:53
Thanks! Good page!
Цитировать