15 KiB
Методы RegExp и String
В JavaScript методы для работы с регулярными выражениями есть в классе RegExp
, а также встроены в обычные строки String
Всего этих методов немного, поэтому мы сначала рассмотрим их по отдельности, а затем -- рецепты по решению стандартных задач с ними.
[cut]
Методы строк
str.search(regexp)
Этот метод мы уже видели.
Он возвращает позицию первого совпадения или -1
, если ничего не найдено.
//+ run
var str = "Люблю регэкспы я, но странною любовью";
alert( str.search( *!*/лю/i*/!* ) ); // 0
Ограничение метода search
-- он всегда ищет только первое совпадение.
Нельзя заставить search
искать дальше первого совпадения, такой синтаксис попросту не предусмотрен. Но есть другие методы, которые это умеют.
str.match(regexp) без флага g, скобочные выражения
Метод str.match
работает по-разному, в зависимости от наличия или отсутствия флага g
, поэтому сначала мы разберём вариант, когда его нет.
В этом случае str.match(regexp)
находит только одно, первое совпадение.
Результат вызова -- это массив, состоящий из этого совпадения, с дополнительными свойствами index
-- позиция, на которой оно обнаружено и input
-- строка, в которой был поиск.
Например:
//+ run
var str = "ОЙ-Ой-ой";
var result = str.match( *!*/ой/i*/!* );
alert( result[0] ); // ОЙ (совпадение)
alert( result.index ); // 0 (позиция)
alert( result.input ); // ОЙ-Ой-ой (поисковая строка)
У этого массива не всегда только один элемент.
Если часть шаблона обозначена скобками, то она станет отдельным элементом массива.
Например:
//+ run
var str = "javascript - это такой язык";
var result = str.match( *!*/JAVA(SCRIPT)/i*/!* );
alert( result[0] ); // javascript (всё совпадение полностью)
alert( result[1] ); // script (часть совпадения, соответствующая скобкам)
// также есть свойства result.index, result.input
Благодаря флагу i
поиск не обращает внимание на регистр буквы, поэтому находит javascript
. При этом часть строки, соответствующая SCRIPT
, выделена в отдельный элемент массива. Позже мы используем это для поиска с заменой.
str.match(regexp) с флагом g
При наличии флага g
, вызов match
возвращает обычный массив из всех совпадений.
Никаких дополнительных свойств у массива в этом случае нет, скобки дополнительных элементов не порождают.
Например:
//+ run
var str = "ОЙ-Ой-ой";
var result = str.match( *!*/ой/ig*/!* );
alert( result ); // ОЙ, Ой, ой
Пример со скобками:
//+ run
var str = "javascript - это такой язык";
var result = str.match( *!*/JAVA(SCRIPT)/gi*/!* );
alert( result[0] ); // javascript
alert( result.length ); // 1
alert( result.index ); // undefined
Из последнего примера видно, что элемент в массиве ровно один, и свойства index
также нет. Такова особенность глобального поиска при помощи match
-- он просто возвращает все совпадения.
Для расширенного глобального поиска, который позволит получить все позиции и, при желании, скобки, нужно использовать метод [:RegExp#exec], которые будет рассмотрен далее.
[warn header="В случае, если совпадений не было, match
возвращает null
"]
Обратите внимание, это важно -- если match
не нашёл совпадений, он возвращает не пустой массив, а именно null
.
Это важно иметь в виду, чтобы не попасть в такую ловушку:
//+ run
var str = "Ой-йой-йой";
alert( str.match( /лю/gi ).length ) // ошибка! нет свойства length у null
[/warn]
str.split(regexp|substr, limit)
Разбивает строку в массив по разделителю -- регулярному выражению regexp
или подстроке substr
.
Обычно мы используем метод split
со строками, вот так:
//+ run
alert( '12-34-56'.split('-') ) // [12, 34, 56]
Можно передать в него и регулярное выражение, тогда он разобьёт строку по всем совпадениям.
Тот же пример с регэкспом:
//+ run
alert( '12-34-56'.split(/-/) ) // [12, 34, 56]
str.replace(regexp, newSubStr|function)
Швейцарский нож для работы со строками, поиска и замены любого уровня сложности.
Его простейшее применение -- поиск и замена подстроки в строке, вот так:
//+ run
// заменить дефис на двоеточие
alert( '12-34-56'.replace("-", ":" ) ) // 12:34-56
При вызове со строкой замены replace
всегда заменяет только первое совпадение.
Чтобы заменить все совпадения, нужно использовать для поиска не строку "-"
, а регулярное выражение /-/g
, причём обязательно с флагом g
:
//+ run
// заменить дефис на двоеточие
alert( '12-34-56'.replace( *!*/-/g*/!*, ":" ) ) // 12:34:56
В строке для замены можно использовать специальные символы:
Спецсимволы | Действие в строке замены |
---|---|
`$$` | Вставляет `"$"`. |
`$&` | Вставляет всё найденное совпадение. |
$` |
Вставляет часть строки до совпадения. |
$'
|
Вставляет часть строки после совпадения. |
$*n*
|
где `n` -- цифра или двузначное число, обозначает `n-ю` по счёту скобку, если считать слева-направо. |
Пример использования скобок и $1
, $2
:
//+ run
var str = "Василий Пупкин";
alert( str.replace( /(Василий) (Пупкин)/ ,'$2, $1') ) // Пупкин, Василий
Ещё пример, с использованием $&
:
//+ run
var str = "Василий Пупкин";
alert( str.replace( /Василий Пупкин/ ,'Великий $&!') ) // Великий Василий Пупкин!
Для ситуаций, который требуют максимально "умной" замены, в качестве второго аргумента предусмотрена функция.
Она будет вызвана для каждого совпадения, и её результат будет вставлен как замена.
Например:
//+ run
var i = 0;
// заменить каждое вхождение "ой" на результат вызова функции
alert( "ОЙ-Ой-ой".replace( /ой/gi, function() { return ++i; }) ); // 1-2-3
Эта функция также получает аргументы:
- `str` -- найденное совпадение,
- `p1, p2, ..., pn` -- содержимое скобок
- `offset` -- позиция, на которой найдено совпадение
- `s` -- исходная строка
Если скобок в регулярном выражении нет, то у функции всегда будет ровно 3 аргумента.
Используем это, чтобы вывести полную информацию о совпадениях:
//+ run
// вывести и заменить все совпадения
function replacer(str, offset, s) {
alert("Найдено: " + str + " на позиции: " + offset + " в строке: " + s);
return ":"
}
var result = "ОЙ-Ой-ой".replace( /ой/gi, replacer);
alert('Результат: ' + result);
Со скобочными выражениями:
//+ run
function replacer(str, name, surname, offset, s) {
return surname +", " + name;
}
alert( str.replace( /(Василий) (Пупкин)/ , replacer) ) // Пупкин, Василий
Функция для замены -- это самое мощное средство, какое только может быть. Она владеет всей информацией о совпадении и имеет доступ к замыканию, поэтому может всё.
Методы объектов RegExp
Регэкспы являются объектами класса [:RegExp].
У них есть два основных метода.
regexp.test(str)
Проверяет, есть ли хоть одно совпадение в строке str
. Возвращает true/false
.
Работает, по сути, так же, как и проверка str.search(regexp) != -1
, например:
//+ run
var str = "Люблю регэкспы я, но странною любовью";
alert( *!*/лю/i*/!*.test(str) ) // true
alert( str.search(*!*/лю/i*/!*) != -1 ) // true
Пример с отрицательным результатом:
//+ run
var str = "Ой, цветёт калина...";
alert( *!*/javascript/i*/!*.test(str) ) // false
alert( str.search(*!*/javascript/i*/!*) != -1 ) // false
regexp.exec(str)
Этот метод -- самое мощное, что только есть для поиска с использованием регулярных выражений.
Он ведёт себя по-разному, в зависимости от того, есть ли у регэкспа флаг g
.
- Если флага `g` нет, то `regexp.exec(str)` ищет и возвращает первое совпадение, является полным аналогом вызова `str.match(regexp)`.
- Если флаг `g` есть, то вызов `regexp.exec` возвращает первое совпадение и *запоминает* его позицию в свойстве `regexp.lastIndex`. Последующий поиск он начнёт уже с этой позиции. Если совпадений не найдено, то сбрасывает `regexp.lastIndex` в ноль.
Второй вариант запуска обычно используют в цикле:
//+ run
var str = 'Многое по JavaScript можно найти на сайте http://javascript.ru';
var regexp = /javascript/ig;
alert("Начальное значение lastIndex: " + regexp.lastIndex);
while( result = regexp.exec(str) ) {
alert('Найдено: ' + result[0] + ' на позиции:' + result.index);
alert('Свойство lastIndex: ' + regexp.lastIndex);
}
alert('Конечное значение lastIndex: ' + regexp.lastIndex);
Здесь цикл продолжается до тех пор, пока regexp.exec
не вернёт null
, что означает "совпадений больше нет".
Найденные результаты последовательно помещаются в result
, причём находятся там в том же формате, что и match
-- с учётом скобок, со свойствами result.index
и result.input
.
[smart header="Поиск с нужной позиции"]
Технически, можно заставить regexp.exec
искать сразу с нужной позиции, если поставить lastIndex
вручную:
//+ run
var str = 'Многое по JavaScript можно найти на сайте http://javascript.ru';
var regexp = /javascript/ig;
regexp.lastIndex = 40;
alert( regexp.exec(str).index ); // 49, поиск начат с 40й позиции
[/smart]
Итого, рецепты
Методы становятся гораздо понятнее, если разбить их использование по задачам, которые нужны в реальной жизни.
- Для поиска только одного совпадения:
- Найти позицию первого совпадения
- `str.search(regexp)`
- Найти само совпадение
- `str.match(regexp)`
- Проверить, есть ли хоть одно совпадение
- `regexp.test(str)`, также можно использовать `str.search(regexp) != -1`
- Найти совпадение с нужной позиции
- `regexp.exec(str)`, начальную позицию поиска задать в `regexp.lastIndex`
- Для поиска всех совпадений:
- Найти массив совпадений
- `str.match(regexp)`, с флагом `g`
- Получить все совпадения, с подробной информацией о каждом
- `regexp.exec(str)` с флагом `g`, в цикле
- Дополнительно:
- Для поиска-и-замены
- `str.replace(regexp, str|func)`
- Для разбивки строки на части
- `str.split(regexp)`
Далее мы перейдём к более подробному изучению синтаксиса регулярных выражений.