Регулярные выражения в javascript имеют особую краткую форму и стандартный PCRE-синтаксис.
Работают они через специальный объект RegExp.
Кроме того, у строк есть свои методы search,match,replace, но чтобы их понять - разберем-таки сначала RegExp.
RegExpОбъект типа RegExp, или, короче, регулярное выражение, можно создать двумя путями
/pattern/флаги
new RegExp("pattern"[, флаги])
pattern - регулярное выражение для поиска (о замене - позже), а флаги - строка из любой комбинации символов g(глобальный поиск), i(регистр неважен) и m(многострочный поиск).
Первый способ используется часто, второй - иногда. Например, два таких вызова эквивалентны:
var reg = /ab+c/i
var reg = new RegExp("ab+c", "i")
При втором вызове - т.к регулярное выражение в кавычках, то нужно дублировать \
// эквивалентны
re = new RegExp("\\w+")
re = /\w+/
При поиске можно использовать большинство возможностей современного PCRE-синтаксиса.
| Символ | Значение |
\ |
Для обычных символов - делает их специальными. Например, выражение /s/ ищет просто символ 's'. А если поставить \ перед s, то /\s/ уже обозначает пробельный символ.И наоборот, если символ специальный, например *, то \ сделает его просто обычным символом "звездочка". Например, /a*/ ищет 0 или больше подряд идущих символов 'a'. Чтобы найти а со звездочкой 'a*' - поставим \ перед спец. символом: /a\*/. |
^ |
Обозначает начало входных данных. Если установлен флаг многострочного поиска ("m"), то также сработает при начале новой строки.Например, /^A/ не найдет 'A' в "an A", но найдет первое 'A' в "An A." |
$ |
Обозначает конец входных данных. Если установлен флаг многострочного поиска, то также сработает в конце строки.Например, /t$/ не найдет 't' в "eater", но найдет - в "eat". |
* |
Обозначает повторение 0 или более раз. Например, /bo*/ найдет 'boooo' в "A ghost booooed" и 'b' в "A bird warbled", но ничего не найдет в "A goat grunted". |
+ |
Обозначает повторение 1 или более раз. Эквивалентно {1,}. Например, /a+/ найдет 'a' в "candy" и все 'a' в "caaaaaaandy". |
? |
Обозначает, что элемент может как присутствовать, так и отсутствовать. Например, /e?le?/ найдет 'el' в "angel" и 'le' в "angle."Если используется сразу после одного из квантификаторов *, +, ?, или {}, то задает "нежадный" поиск (повторение минимально возможное количество раз, до ближайшего следующего элемента паттерна), в противоположность "жадному" режиму по умолчанию, при котором количество повторений максимально, даже если следующий элемент паттерна тоже подходит.Кроме того, ? используется в предпросмотре, который описан в таблице под (?=), (?!), и (?: ). |
. |
(Десятичная точка) обозначает любой символ, кроме перевода строки: \n \r \u2028 or \u2029. (можно использовать [\s\S] для поиска любого символа, включая переводы строк). Например, /.n/ найдет 'an' и 'on' в "nay, an apple is on the tree", но не 'nay'. |
( |
Находит и запоминает. Это называется "запоминающие скобки". Например, /(foo)/ найдет и запомнит 'foo' в "foo bar." Найденная подстрока хранится в массиве-результате поиска или в предопределенных свойствах объекта RegExp: $1, ..., $9.Кроме того, скобки объединяют то, что в них находится, в единый элемент паттерна. Например, (abc)* - повторение abc 0 и более раз. |
(?: |
Находит , но не запоминает найденное. Это называется "незапоминающие скобки". Найденная подстрока не сохраняется в массиве результатов и свойствах RegExp.Как и все скобки, объединяют находящееся в них в единый подпаттерн. |
|
Находит , только если за следует . Например, /Jack(?=Sprat)/ найдет 'Jack', только если за ним следует 'Sprat'. /Jack(?=Sprat|Frost)/ найдет 'Jack', только если за ним следует 'Sprat' или 'Frost'. Однако, ни 'Sprat' ни 'Frost' не войдут в результат поиска. |
|
Находит , только если за не следует . Например, /\d+(?!\.)/ найдет число, только если за ним не следует десятичная точка. /\d+(?!\.)/.exec("3.141") найдет 141, но не 3.141. |
|
Находит или . Например, /green|red/ найдет 'green' в "green apple" и 'red' в "red apple." |
{ |
Где n - положительное целое число. Находит ровно n повторений предшествующего элемента. Например, /a{2}/ не найдет 'a' в "candy," но найдет оба a в "caandy," и первые два a в "caaandy." |
{ |
Где n - положительное целое число. Находит n и более повторений элемента. Например, /a{2,} не найдет 'a' в "candy", но найдет все 'a' в "caandy" и в "caaaaaaandy." |
{ |
Где n и m - положительные целые числа. Находят от n до m повторений элемента. |
[ |
Набор символов. Находит любой из перечисленных символов. Вы можете указать промежуток, используя тире. Например, [abcd] - то же самое, что [a-d]. Найдет 'b' в "brisket", а также 'a' и 'c' в "ache". |
[^ |
Любой символ, кроме указанных в наборе. Вы также можете указать промежуток. Например, [^abc] - то же самое, что [^a-c]. Найдет 'r' в "brisket" и 'h' в "chop." |
[\b] |
Находит символ backspace. (Не путать с \b.) |
\b |
Находит границу слов (латинских), например пробел. (Не путать с [\b]). Например, /\bn\w/ найдет 'no' в "noonday"; /\wy\b/ найдет 'ly' в "possibly yesterday." |
\B |
Обозначает не границу слов. Например, /\w\Bn/ найдет 'on' в "noonday", а /y\B\w/ найдет 'ye' в "possibly yesterday." |
\c |
- буква от A до Z. Обозначает контрольный символ в строке. Например, /\cM/ обозначает символ Ctrl-M. |
\d |
находит цифру из любого алфавита (у нас же юникод). Испльзуйте [0-9], чтобы найти только обычные цифры. Например, /\d/ или /[0-9]/ найдет '2' в "B2 is the suite number." |
\D |
Найдет нецифровой символ (все алфавиты). [^0-9] - эквивалент для обычных цифр. Например, /\D/ или /[^0-9]/ найдет 'B' в "B2 is the suite number." |
\f,\r,\n |
Соответствующие спецсимволы form-feed, line-feed, перевод строки. |
\s |
Найдет любой пробельный символ, включая пробел, табуляцию, переводы строки и другие юникодные пробельные символы. Например, /\s\w*/ найдет ' bar' в "foo bar." |
\S |
Найдет любой символ, кроме пробельного. Например, /\S\w*/ найдет 'foo' в "foo bar." |
\t |
Символ табуляции. |
\v |
Символ вертикальной табуляции. |
\w |
Найдет любой словесный (латинский алфавит) символ, включая буквы, цифры и знак подчеркивания. Эквивалентно [A-Za-z0-9_]. Например, /\w/ найдет 'a' в "apple," '5' в "$5.28," и '3' в "3D." |
\W |
Найдет любой не-(лат.)словесный символ. Эквивалентно [^A-Za-z0-9_]. Например, /\W/ и /[^$A-Za-z0-9_]/ одинаково найдут '%' в "50%." |
\ |
где - целое число. Обратная ссылка на n-ю запомненную скобками подстроку. Например, /apple(,)\sorange\1/ найдет 'apple, orange,' в "apple, orange, cherry, peach.". За таблицей есть более полный пример. |
\0 |
Найдет символ NUL. Не добавляйте в конец другие цифры. |
\x |
Найдет символ с кодом (2 шестнадцатиричных цифры) |
\u |
Найдет символ с кодом (4 шестнадцатиричных цифры). |
testЧтобы просто проверить, подходит ли строка под регулярное выражение, используется метод test:
if ( /\s/.test("строка") ) {
...В строке есть пробелы!...
}
Метод test начинает поиск, начиная со свойства lastIndex объекта RegExp, если оно установлено.
execМетод exec возвращает массив и ставит свойства регулярного выражения.
Если совпадений нет, то возвращается null.
Например,
// Найти одну d, за которой следует 1 или более b, за которыми одна d
// Запомнить найденные b и следующую за ними d
// Регистронезависимый поиск
var myRe = /d(b+)(d)/ig;
var myArray = myRe.exec("cdbBdbsbz");
В результате выполнения скрипта будут такие результаты:
| Объект | Свойство/Индекс | Описания | Пример |
myArray |
|
Содержимое myArray. |
["dbBd", "bB", "d"] |
index |
Индекс совпадения (от 0) | 1 |
|
input |
Исходная строка. | cdbBdbsbz |
|
[0] |
Последние совпавшие символы | dbBd |
|
[1], ...[ |
Совпадения во вложенных скобках, если есть. Число вложенных скобок не ограничено. | [1] = bB |
|
myRe |
lastIndex |
Индекс, с которого начинать следующий поиск. | 5 |
ignoreCase |
Показывает, что был включен регистронезависимый поиск, флаг "i". |
true |
|
global |
Показывает, что был включен флаг "g" поиска всех совпадений. |
true |
|
multiline |
Показывает, был ли включен флаг многострочного поиска "m". |
false |
|
source |
Текст паттерна. | d(b+)(d) |
Если в регулярном выражении включен флаг "g", Вы можете вызывать метод exec много раз для поиска последовательных совпадений в той же строке. Когда Вы это делаете, поиск начинается на подстроке str, с индекса lastIndex. Например, вот такой скрипт:
var myRe = /ab*/g;
var str = "abbcdefabh";
while ((myArray = myRe.exec(str)) != null) {
var msg = "Found " + myArray[0] + ". ";
msg += "Next match starts at " + myRe.lastIndex;
print(msg);
}
Этот скрипт выведет следующий текст:
Found abb. Next match starts at 3 Found ab. Next match starts at 9
В следующем примере функция выполняет поиск по input. Затем делается цикл по массиву, чтобы посмотреть, есть ли другие имена.
Предполагается, что все зарегистрированные имена находятся в массиве А:
var A = ["Frank", "Emily", "Jane", "Harry", "Nick", "Beth", "Rick",
"Terrence", "Carol", "Ann", "Terry", "Frank", "Alice", "Rick",
"Bill", "Tom", "Fiona", "Jane", "William", "Joan", "Beth"];
function lookup(input)
{
var firstName = /\w+/i.exec(input);
if (!firstName)
{
print(input + " isn't a name!");
return;
}
var count = 0;
for (var i = 0; i < A.length; i++)
{
if (firstName[0].toLowerCase() == A[i].toLowerCase())
count++;
}
var midstring = (count == 1) ? " other has " : " others have ";
print("Thanks, " + count + midstring + "the same name!")
}
Следующие методы работают с регулярными выражениями из строк.
Все методы, кроме replace, можно вызывать как с объектами типа regexp в аргументах, так и со строками, которые автоматом преобразуются в объекты RegExp.
Так что вызовы эквивалентны:
var i = str.search(/\s/)
var i = str.search("\\s")
При использовании кавычек нужно дублировать \ и нет возможности указать флаги. Если регулярное выражение уже задано строкой, то бывает удобна и полная форма
var regText = "\\s" var i = str.search(new RegExp(regText, "g"))
search(regexp)Возвращает индекс регулярного выражения в строке, или -1.
Если Вы хотите знать, подходит ли строка под регулярное выражение, используйте метод search(аналогично RegExp-методы test). Чтобы получить больше информации, используйте более медленный метод match(аналогичный методу RegExp exec).
Этот пример выводит сообщение, в зависимости от того, подходит ли строка под регулярное выражение.
function testinput(re, str){
if (str.search(re) != -1)
midstring = " contains ";
else
midstring = " does not contain ";
document.write (str + midstring + re.source);
}
match(regexp)Если в regexp нет флага g, то возвращает тот же результат, что regexp.exec(string).
Если в regexp есть флаг g, то возвращает массив со всеми совпадениями.
Чтобы просто узнать, подходит ли строка под регулярное выражение regexp, используйте regexp.test(string).
Если Вы хотите получить первый результат - попробуйте regexp.exec(string).
В следующем примере match используется, чтобы найти "Chapter", за которой следует 1 или более цифр, а затем цифры, разделенные точкой. В регулярном выражении есть флаг i, так что регистр будет игнорироваться.
str = "For more information, see Chapter 3.4.5.1"; re = /chapter (\d+(\.\d)*)/i; found = str.match(re); alert(found);
Скрипт выдаст массив из совпадений:
Следующий пример демонстрирует использование флагов глобального и регистронезависимого поиска с match. Будут найдены все буквы от А до Е и от а до е, каждая - в отдельном элементе массива.
var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; var regexp = /[A-E]/gi; var matches = str.match(regexp); document.write(matches); // matches = ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']
replaceМетод replace может заменять вхождения регулярного выражения не только на строку, но и на результат выполнения функции. Его полный синтаксис - такой:
var newString = str.replace(regexp/substr, newSubStr/function)
regexp substr newSubStr. newSubStr function Метод replace не меняет строку, на которой вызван, а просто возвращает новую, измененную строку.
Чтобы осуществить глобальную замену, включите в регулярное выражение флаг "g".
Если первый аргумент - строка, то она не преобразуется в регулярное выражение, так что, например,
var ab = "a b".replace("\\s","..") // = "a b"
Вызов replace оставил строку без изменения, т.к искал не регулярное выражение \s, а строку "\s".
В строке замены могут быть такие спецсимволы:
| Pattern | Inserts |
$$ |
Вставляет "$". |
$& |
Вставляет найденную подстроку. |
$` |
Вставляет часть строки, которая предшествует найденному вхождению. |
$' |
Вставляет часть строки, которая идет после найденного вхождения. |
$ or $ |
Где или - десятичные цифры, вставляет подстроку вхождения, запомненную n-й вложенной скобкой, если первый аргумент - объект RegExp. |
Если Вы указываете вторым параметром функцию, то она выполняется при каждом совпадении.
В функции можно динамически генерировать и возвращать строку подстановки.
Первый параметр функции - найденная подстрока. Если первым аргументом replace является объект RegExp, то следующие n параметров содержат совпадения из вложенных скобок. Последние два параметра - позиция в строке, на которой произошло совпадение и сама строка.
Например, следующий вызов replace возвратит XXzzzz - XX , zzzz.
function replacer(str, p1, p2, offset, s)
{
return str + " - " + p1 + " , " + p2;
}
var newString = "XXzzzz".replace(/(X*)(z*)/, replacer)
Как видите, тут две скобки в регулярном выражении, и потому в функции два параметра p1, p2.
Если бы были три скобки, то в функцию пришлось бы добавить параметр p3.
Следующая функция заменяет слова типа borderTop на border-top:
function styleHyphenFormat(propertyName)
{
function upperToHyphenLower(match)
{
return '-' + match.toLowerCase();
}
return propertyName.replace(/[A-Z]/, upperToHyphenLower);
}
В некоторых реализациях javascript регэкспы, заданные коротким синтаксисом /.../ - статичны. То есть, такой объект создается один раз в некоторых реализациях JS, например в Firefox. В Chrome все ок.
function f() {
// при многократных заходах в функцию объект один и тот же
var re = /lalala/
}
По стандарту эта возможность разрешена ES3, но запрещена ES5.
Из-за того, что lastIndex при глобальном поиске меняется, а сам объект регэкспа статичен, первый поиск увеличивает lastIndex, а последующие - продолжают искать со старого lastIndex, т.е. могут возвращать не все результаты.
При поиске всех совпадений в цикле проблем не возникает, т.к. последняя итерация (неудачная) обнуляет lastIndex.
Для общего понимания регулярных выражений можно почитать Статью в wikipedia.
Более подробно они описаны в книге (англ.) Beginning Regular Expressions.