Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
247 lines (149 sloc) 12.4 KB

Классы и спецсимволы

Рассмотрим практическую задачу -- есть телефонный номер "+7(903)-123-45-67", и нам нужно найти в этой строке цифры. А остальные символы нас не интересуют.

Для поиска символов определённого вида в регулярных выражениях предусмотрены "классы символов".

Класс символов -- это специальное обозначение, под которое подходит любой символ из определённого набора.

Например, есть класс "любая цифра". Он обозначается \d. Это обозначение вставляется в шаблон, и при поиске под него подходит любая цифра.

То есть, регулярное выражение pattern:/\d/ ищет ровно одну цифру:

var str = "+7(903)-123-45-67";

var reg = /\d/;

// не глобальный регэксп, поэтому ищет только первую цифру
alert( str.match(reg) ); // 7

...Ну а для поиска всех цифр достаточно добавить к регэкспу флаг g:

var str = "+7(903)-123-45-67";

var reg = /\d/g;

alert( str.match(reg) ); // массив всех совпадений: 7,9,0,3,1,2,3,4,5,6,7

Важнейшие классы: \d \s \w

Это был класс для цифр.

Конечно же, есть и другие.

Наиболее часто используются:

\d (от английского "digit" -- "цифра") : Цифра, символ от 0 до 9.

\s (от английского "space" -- "пробел") : Пробельный символ, включая табы, переводы строки и т.п.

\w (от английского "word" -- "слово") : Символ "слова", а точнее -- буква латинского алфавита или цифра или подчёркивание '_'. Не-английские буквы не являются \w, то есть русская буква не подходит.

Например, pattern:\d\s\w обозначает цифру, за которой идёт пробельный символ, а затем символ слова.

Регулярное выражение может содержать одновременно и обычные символы и классы.

Например, pattern:CSS\d найдёт строку match:CSS, с любой цифрой после неё:

var str = "Стандарт CSS4 - это здорово";
var reg = /CSS\d/

alert( str.match(reg) ); // CSS4

И много классов подряд:

alert( "Я люблю HTML5!".match(/\s\w\w\w\w\d/) ); // 'HTML5'

Совпадение (каждому классу в регэкспе соответствует один символ результата):

Граница слова \b

Граница слова pattern:\b -- это особый класс.

Он интересен тем, что обозначает не символ, а границу между символами.

Например, pattern:\bJava\b найдёт слово match:Java в строке subject:Hello, Java!, но не в строке subject:Hello, Javascript!.

alert( "Hello, Java!".match(/\bJava\b/) ); // Java
alert( "Hello, Javascript!".match(/\bJava\b/) ); // null

Граница имеет "нулевую ширину" в том смысле, что обычно символам регулярного выражения соответствуют символы строки, но не в этом случае.

Граница -- это проверка.

При поиске движок регулярных выражений идёт по шаблону и одновременно по строке, пытаясь построить соответствие. Когда он видит pattern:\b, то проверяет, что текущая позиция в строке подходит под одно из условий:

  • Начало текста, если первый символ \w.
  • Конец текста, если последний символ \w.
  • Внутри текста, если с одной стороны \w, а с другой -- не \w.

Например, в строке subject:Hello, Java! под \b подходят следующие позиции:

Как правило, \b используется, чтобы искать отдельно стоящее слово. Не на русском конечно, хотя подобную проверку, как мы увидим далее, можно легко сделать для любого языка. А вот на английском, как в примере выше или для чисел, которые являются частным случаем \w -- легко.

Например, регэксп pattern:\b\d\d\b ищет отдельно двузначные числа. Иными словами, он требует, чтобы до и после pattern:\d\d был символ, отличный от \w (или начало/конец текста).

Обратные классы

Для каждого класса существует "обратный ему", представленный такой же, но заглавной буквой.

"Обратный" -- означает, что ему соответствуют все остальные символы, например:

\D : Не-цифра, то есть любой символ кроме \d, например буква.

\S : Не-пробел, то есть любой символ кроме \s, например буква.

\W : Любой символ, кроме \w, то есть не латинница, не подчёркивание, не цифра. В частности, русские буквы принадлежат этому классу.

\B : Проверка, обратная \b.

В начале этой главы мы видели, как получить из телефона subject:+7(903)-123-45-67 все цифры.

Первый способ -- найти все цифры через match(/\d/g).

Обратные классы помогут реализовать альтернативный -- найти все НЕцифры и удалить их из строки:

var str = "+7(903)-123-45-67";

alert( str.replace(/\D/g, "") ); // 79031234567

Пробелы -- обычные символы

Заметим, что в регулярных выражениях пробел -- такой же символ, как и другие.

Обычно мы не обращаем внимание на пробелы. Для нашего взгляда строки subject:1-5 и subject:1 - 5 почти идентичны.

Однако, если регэксп не учитывает пробелов, то он не сработает.

Попытаемся найти цифры, разделённые дефисом:

alert( "1 - 5".match(/\d-\d/) ); // null, нет совпадений!

Поправим это, добавив в регэксп пробелы:

alert( "1 - 5".match(/\d - \d/) ); // работает, пробелы вокруг дефиса

Конечно же, пробелы в регэкспе нужны лишь тогда, когда мы их ищем. Лишние пробелы (как и любые лишние символы) могут навредить:

alert( "1-5".match(/\d - \d/) ); // null, так как в строке 1-5 нет пробелов

Короче говоря, в регулярном выражении все символы имеют значение. Даже (и тем более) -- пробелы.

Точка -- любой символ

Особым классом символов является точка ".".

В регулярном выражении, точка pattern:"." обозначает любой символ, кроме перевода строки:

alert( "Z".match(/./) ); // найдено Z

Посередине регулярного выражения:

var re = /CS.4/;

alert( "CSS4".match(re) ); // найдено "CSS4"
alert( "CS-4".match(re) ); // найдено "CS-4"
alert( "CS 4".match(re) ); // найдено "CS 4" (пробел тоже символ)

Обратим внимание -- точка означает именно "произвольный символ".

То есть какой-то символ на этом месте в строке должен быть:

alert( "CS4".match(/CS.4/) ); // нет совпадений, так как для точки нет символа

Экранирование специальных символов

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

Они используются, чтобы расширить возможности поиска.

Вот их полный список: pattern:[ \ ^ $ . | ? * + ( ).

Не пытайтесь запомнить его -- когда мы разберёмся с каждым из них по отдельности, он запомнится сам собой.

Чтобы использовать специальный символ в качестве обычного, он должен быть экранирован.

Или, другими словами, перед символом должен быть обратный слэш '\'.

Например, нам нужно найти точку pattern:'.'. В регулярном выражении она означает "любой символ, кроме новой строки", поэтому чтобы найти именно сам символ "точка" -- её нужно экранировать: pattern:\..

alert( "Глава 5.1".match(/\d\.\d/) ); // 5.1

Круглые скобки также являются специальными символами, так что для поиска именно скобки нужно использовать \(. Пример ниже ищет строку "g()":

alert( "function g()".match(/g\(\)/) ); // "g()"

Сам символ слэш '/', хотя и не является специальными символом в регулярных выражениях, но открывает-закрывает регэксп в синтаксисе pattern:/...pattern.../, поэтому его тоже нужно экранировать.

Так выглядит поиск слэша '/':

alert( "/".match(/\//) ); // '/'

Ну и, наконец, если нам нужно найти сам обратный слэш \, то его нужно просто задублировать.

Так выглядит поиск обратного слэша "\":

alert( "1\2".match(/\\/) ); // '\'

Итого

Мы рассмотрели классы для поиска типов символов:

  • \d -- цифры.
  • \D -- не-цифры.
  • \s -- пробельные символы, переводы строки.
  • \S -- всё, кроме \s.
  • \w -- латинница, цифры, подчёркивание '_'.
  • \W -- всё, кроме \w.
  • '.' -- точка обозначает любой символ, кроме перевода строки.

Если хочется поискать именно сочетание "\d" или символ "точка", то его экранируют обратным слэшем, вот так: pattern:\.

Заметим, что регулярное выражение может также содержать перевод строки \n, табуляцию \t и прочие спецсимволы для строк. Конфликта с классами не происходит, так как для них зарезервированы другие буквы.