# Классы и спецсимволы
Рассмотрим практическую задачу -- есть телефонный номер `"+7(903)-123-45-67"`, и нам нужно найти в этой строке цифры. А остальные символы нас не интересуют.
Для поиска символов определённого вида в регулярных выражениях предусмотрены "классы символов".
[cut]
Класс символов -- это специальное обозначение, под которое подходит любой символ из определённого набора.
Например, есть класс "любая цифра". Он обозначается `\d`. Это обозначение вставляется в шаблон, и при поиске под него подходит любая цифра.
То есть, регулярное выражение /\d/
ищет ровно одну цифру:
```js
//+ run
var str = "+7(903)-123-45-67";
var reg = /\d/;
// не глобальный регэксп, поэтому ищет только первую цифру
alert( str.match(reg) ); // 7
```
...Ну а для поиска всех цифр достаточно добавить к регэкспу флаг `g`:
```js
//+ run
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\s\w
обозначает цифру, за которой идёт пробельный символ, а затем символ слова.
Регулярное выражение может содержать одновременно и обычные символы и классы.
Например, CSS\d
найдёт строку CSS
, с любой цифрой после неё:
```js
//+ run
var str = "Стандарт CSS4 - это здорово";
var reg = /CSS\d/
alert( str.match(reg) ); // CSS4
```
И много классов подряд:
```js
//+ run
alert( "Я люблю HTML5!".match(/\s\w\w\w\w\d/) ); // 'HTML5'
```
Совпадение (каждому классу в регэкспе соответствует один символ результата):
\b
-- это особый класс.
Он интересен тем, что обозначает не символ, а границу между символами.
Например, \bJava\b
найдёт слово Java
в строке Hello, Java!
, но не в строке Hello, Javascript!
.
```js
//+ run
alert( "Hello, Java!".match(/\bJava\b/) ); // Java
alert( "Hello, Javascript!".match(/\bJava\b/) ); // null
```
Граница имеет "нулевую ширину" в том смысле, что обычно символам регулярного выражения соответствуют символы строки, но не в этом случае.
Граница -- это проверка.
При поиске движок регулярных выражений идёт по шаблону и одновременно по строке, пытаясь построить соответствие. Когда он видит \b
, то проверяет, что текущая позиция в строке подходит под одно из условий:
Hello, Java!
под `\b` подходят следующие позиции:
\b\d\d\b
ищет отдельно двузначные числа. Иными словами, он требует, чтобы до и после \d\d
был символ, отличный от `\w` (или начало/конец текста).
## Обратные классы
Для каждого класса существует "обратный ему", представленный такой же, но заглавной буквой.
"Обратный" -- означает, что ему соответствуют все остальные символы, например:
+7(903)-123-45-67
все цифры.
Первый способ -- найти все цифры через `match(/\d/g)`.
Обратные классы помогут реализовать альтернативный -- найти все НЕцифры и удалить их из строки:
```js
//+ run
var str = "+7(903)-123-45-67";
alert( str.replace(/\D/g, "") ); // 79031234567
```
## Пробелы -- обычные символы
Заметим, что в регулярных выражениях пробел - такой же символ, как и другие.
Обычно мы не обращаем внимание на пробелы. Для нашего взгляда строки 1-5
и 1 - 5
почти идентичны.
Однако, если регэксп не учитывает пробелов, то он не сработает.
Попытаемся найти цифры, разделённые дефисом:
```js
//+ run
alert( "1 - 5".match(/\d-\d/) ); // null, нет совпадений!
```
Поправим это, добавив в регэксп пробелы:
```js
//+ run
alert( "1 - 5".match(/\d - \d/) ); // работает, пробелы вокруг дефиса
```
Конечно же, пробелы в регэкспе нужны лишь тогда, когда мы их ищем. Лишние пробелы (как и любые лишние символы) могут навредить:
```js
//+ run
alert( "1-5".match(/\d - \d/) ); // null, так как в строке 1-5 нет пробелов
```
Короче говоря, в регулярном выражении все символы имеют значение. Даже (и тем более) -- пробелы.
## Точка -- любой символ
Особым классом символов является точка `"."`.
В регулярном выражении, точка "."
обозначает *любой символ*, кроме перевода строки:
```js
//+ run
alert( "Z".match(/./) ); // найдено Z
```
Посередине регулярного выражения:
```js
//+ run
var re = /CS.4/;
alert( "CSS4".match(re) ); // найдено "CSS4"
alert( "CS-4".match(re) ); // найдено "CS-4"
alert( "CS 4".match(re) ); // найдено "CS 4" (пробел тоже символ)
```
Обратим внимание -- точка означает именно "произвольный символ".
То есть какой-то символ на этом месте в строке должен быть:
```js
//+ run
alert( "CS4".match(/CS.4/) ); // нет совпадений, так как для точки нет символа
```
## Экранирование специальных символов
В регулярных выражениях есть и другие символы, имеющие особый смысл.
Они используются, чтобы расширить возможности поиска.
Вот их полный список: [ \ ^ $ . | ? * + ( )
.
Не пытайтесь запомнить его -- когда мы разберёмся с каждым из них по отдельности, он запомнится сам собой.
**Чтобы использовать специальный символ в качестве обычного, он должен быть *экранирован*.**
Или, другими словами, перед символом должен быть обратный слэш `'\'`.
Например, нам нужно найти точку '.'
. В регулярном выражении она означает "любой символ, кроме новой строки", поэтому чтобы найти именно сам символ "точка" -- её нужно экранировать: \.
.
```js
//+ run
alert( "Глава 5.1".match(/\d\.\d/) ); // 5.1
```
Круглые скобки также являются специальными символами, так что для поиска именно скобки нужно использовать `\(`. Пример ниже ищет строку `"g()"`:
```js
//+ run
alert( "function g()".match(/g\(\)/) ); // "g()"
```
Сам символ слэш `'/'`, хотя и не является специальными символом в регулярных выражениях, но открывает-закрывает регэксп в синтаксисе /...pattern.../
, поэтому его тоже нужно экранировать.
Так выглядит поиск слэша `'/'`:
```js
//+ run
alert( "/".match(/\//) ); // '/'
```
Ну и, наконец, если нам нужно найти сам обратный слэш `\`, то его нужно просто задублировать.
Так выглядит поиск обратного слэша `"\"`:
```js
//+ run
alert( "1\2".match(/\\/) ); // '\'
```
## Итого
Мы рассмотрели классы для поиска типов символов:
\.
Заметим, что регулярное выражение может также содержать перевод строки `\n`, табуляцию `\t` и прочие спецсимволы для строк. Конфликта с классами не происходит, так как для них зарезервированы другие буквы.