en.javascript.info/11-regular-expressions-javascript/3-regexp-character-classes/article.md
2015-04-05 23:59:54 +03:00

13 KiB
Raw Blame History

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

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

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

[cut]

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

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

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

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

var reg = /\d/;

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

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

//+ 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` (от английского "digit" - "цифра")
Цифра, символ от `0` до `9`.
`\s` (от английского "space" - "пробел")
Пробельный символ, включая табы, переводы строки и т.п.
`\w` (от английского "word" -- "слово")
Символ "слова", а точнее -- буква латинского алфавита или цифра или подчёркивание `'_'`. Не-английские буквы не являются `\w`, то есть русская буква не подходит.

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

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

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

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

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

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

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

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

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

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

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

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

//+ run

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

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

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

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

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

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

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

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

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

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

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

`\D`
Не-цифра, то есть любой символ кроме `\d`, например буква.
`\S`
Не-пробел, то есть любой символ кроме `\s`, например буква.
`\W`
Любой символ, кроме `\w`, то есть не латинница, не подчёркивание, не цифра. В частности, русские буквы принадлежат этому классу.
`\B`
Проверка, обратная `\b`.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

//+ run
var re = /CS.4/;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Итого

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

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

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

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