Регулярні вирази і спеціальні символи

Регулярні вирази в javascript мають особливу коротку форму і стандартний PCRE-синтаксис.

Працюють вони через спеціальний об'єкт RegExp.

Крім того, у рядків є свої методи search, match, replace, але щоб їх зрозуміти - розберемо-таки спочатку 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 '.
(X) Знаходить x і запам'ятовує. Це називається "запам'ятовуючі дужки". Наприклад, / (foo) / знайде і запам'ятає 'foo' в "foo bar." Знайдена підрядок зберігається в масиві-результаті пошуку або в зумовлених властивості об'єкта RegExp: $ 1, ..., $ 9 .Крім того, дужки об'єднують те, що в них знаходиться, в єдиний елемент патерну. Наприклад, (abc) * - повторення abc 0 і більше разів.
(?: X) Знаходить x, але не запам'ятовує знайдене. Це називається "не запам'ятовуються дужки". Знайдена підрядка не зберігається в масиві результатів і властивості RegExp.Как і всі дужки, об'єднують що знаходиться в них в єдиний подпаттерн.
x (? = y) Знаходить x, тільки якщо за x слід y. Наприклад, / Jack (? = Sprat) / знайде 'Jack', тільки якщо за ним слід 'Sprat'. / Jack (? = Sprat | Frost) / знайде 'Jack', тільки якщо за ним слід 'Sprat' або 'Frost'. Однак, ні 'Sprat' nor 'Frost' не ввійдуть в результат пошуку.
x (?! y) Знаходить x, тільки якщо за x не слід y. Наприклад, /\d+(?!\.)/ знайде число, тільки якщо за ним не слід десяткова крапка. /\d+(?!\.)/.exec("3.141 ") знайде 141, але не 3.141.
x | y Знаходить x або y. Наприклад, / green | red / знайде 'green' в "green apple" та 'red' в "red apple."
{N} Де n - позитивне ціле число. Знаходить рівно n повторення попереднього елемента. Наприклад, / a {2} / не знайде 'a' в "candy," але знайде обидва a в "caandy," і перші два a в "caaandy."
{N,} Де n - позитивне ціле число. Знаходить n і більш повторень елемента. Наприклад, / a {2} не знайде 'a' в "candy", але знайде все 'a' в "caandy" і в "caaaaaaandy."
{N, m} Де n і m - позитивні цілі числа. Знаходять від n до m повторень елемента.
[Xyz] Набір символів. Знаходить будь-який з перелічених символів. Ви можете вказати проміжок, використовуючи тире. Наприклад, [abcd] - те ж саме, що [ad]. Знайде 'b' в "brisket", а також 'a' і 'c' в "ache".
[^ Xyz] Будь-який символ, крім зазначених у наборі. Ви також можете вказати проміжок. Наприклад, [^ abc] - те ж саме, що [^ ac]. Знайде '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 X Де X - буква від 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 де n - ціле число. Зворотній посилання на n-ю запомненную дужками підрядок. Наприклад, / apple (,) \ sorange \ 1 / знайде 'apple, orange,' в "apple, orange, cherry, peach.". За таблицею є більш повний приклад.
\ 0 Знайде символ NUL. Не додавайте в кінець інші цифри.
\ x hh Знайде символ з кодом hh (2 шістнадцяткових цифри)
\ u hhhh Знайде символ з кодом hhhh (4 шістнадцяткових цифри).

Щоб просто перевірити, чи підходить рядок під регулярний вираз, використовується метод test:

if (/\s/.test("строка ")) {
... У рядку є прогалини! ...
}

Метод 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], ... [n] Збіги у вкладених дужках, якщо є. Число вкладених дужок не обмежена. [1] = bB
[2] = d
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 + "is not 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 i = str.search (new RegExp ( "\\ s", "g"))

Повертає індекс регулярного вираження в рядку, або -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);
}

Якщо в regexp немає прапора g, то повертає той же результат, що regexp.exec (string).

Якщо в regexp є прапор g, то повертає масив з усіма збігами.

Щоб просто дізнатися, чи підходить рядок під регулярний вираз regexp, використовуйте regexp.test (string).

Якщо Ви хочете отримати перший результат - спробуйте r egexp.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);

Скрипт видасть масив з збігів:

  • Chapter 3.4.5.1 - повністю збіглася рядок
  • 3.4.5.1 - перша дужка
  • .1 - Внутрішня дужка

Наступний приклад демонструє використання прапорів глобального і регістронезавісімого пошуку з match. Будуть знайдені всі літери від А до Е і від а до е, кожна - в окремому елементі масиву.

var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var regexp = / [AE] / gi;
var matches = str.match (regexp);
document.write (matches);
// Matches = [ 'A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']

Метод replace може заміняти входження регулярного вираження не тільки на рядок, а й на результат виконання функції. Його повний синтаксис - такий:

var newString = str.replace (regexp / substr, newSubStr / function)
regexp
Об'єкт RegExp. Його входження будуть замінені на значення, яке поверне параметр номер 2
substr
Рядок, яка буде замінена на newSubStr.
newSubStr
Рядок, яка замінює підрядок з аргументу номер 1.
function
Функція, яка може бути викликана для генерації нової підрядка (щоб підставити її замість підрядка, отриманої з аргументу 1).

Метод replace не змінює рядок, на якій викликаний, а просто повертає нову, змінену рядок.

Щоб здійснити глобальну заміну, включіть в регулярний вираз прапор "g".

Якщо перший аргумент - рядок, то вона не перетвориться в регулярний вираз, так що, наприклад,

var ab = "ab" .replace ( "\\ s", "..") // = "ab"

Виклик replace залишив рядок без зміни, т.к шукати не регулярний вираз \ s, а рядок "\ s".

У рядку заміни можуть бути такі спецсимволи:

Pattern Inserts
$$ Вставляє "$".
$ & Вставляє знайдену підрядок.
$ ` Вставляє частина рядка, яка передує знайденому входженню.
$ ' Вставляє частина рядка, яка йде після знайденого входження.
$ N or $ nn Де n або nn - десяткові цифри, вставляє підрядок входження, запомненную 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 (/ [AZ] /, upperToHyphenLower);
}

Для загального розуміння регулярних виразів можна почитати Статтю в wikipedia .

Більш докладно вони описані в книзі (англ.) Beginning Regular Expressions .