en.javascript.info/11-regular-expressions-javascript/5-regexp-character-sets-and-ranges/article.md
2015-03-24 00:03:51 +03:00

170 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Наборы и диапазоны [...]
Если в регулярном выражении несколько символов или символьных классов заключены в квадратные скобки `[…]`, то это означает "искать любой символ из указанных в `[…]`".
[cut]
## Набор
Например, <code class="pattern">[еао]</code> означает любой символ из этих трёх: `'а'`, `'е'`, или `'о'`.
Такое обозначение называют *набором*. Наборы используются в регулярном выражении наравне с обычными символами:
```js
//+ run
// найти [г или т], а затем "оп"
alert( "Гоп-стоп".match(/[гт]оп/gi) ); // "Гоп", "топ"
```
Обратим внимание: несмотря на то, что в наборе указано несколько символов, в совпадении должен присутствовать *ровно один* из них.
Поэтому в примере ниже нет результатов:
```js
//+ run
// найти "В", затем [у или а], затем "ля"
alert( "Вуаля".match(/В[уа]ля/) ); // совпадений нет
```
Поиск подразумевает:
<ul>
<li><code class="pattern">В</code>,</li>
<li>затем *одну* из букв набора <code class="pattern">[уа]</code>,</li>
<li>а затем <code class="pattern">ля</code></li>
</ul>
Таким образом, совпадение было бы для строки <code class="match">Вуля</code> или <code class="match">Валя</code>.
## Диапазоны
Квадратные скобки могут также содержать *диапазоны символов*.
Например, <code class="pattern">[a-z]</code> -- произвольный символ от `a` до `z`, <code class="pattern">[0-5]</code> -- цифра от `0` до `5`.
В примере ниже мы будем искать `"x"`, после которого идёт два раза любая цифра или буква от A до F:
```js
//+ run
// найдёт "xAF"
alert( "Exception 0xAF".match(/x[0-9A-F][0-9A-F]/g) );
```
Обратим внимание, в слове <code class="subject">Exception</code> есть сочетание <code class="subject">xce</code>, но оно не подошло, потому что буквы в нём маленькие, а в диапазоне <code class="pattern">[0-9A-F]</code> -- большие.
Если хочется искать и его тоже, можно добавить в скобки диапазон `a-f`: <code class="pattern">[0-9A-Fa-f]</code>. Или же просто указать у всего регулярного выражения флаг `i`.
**Символьные классы -- всего лишь более короткие записи для диапазонов, в частности:**
<ul>
<li>**\d** -- то же самое, что <code class="pattern">[0-9]</code>,</li>
<li>**\w** -- то же самое, что <code class="pattern">[a-zA-Z0-9_]</code>,</li>
<li>**\s** -- то же самое, что <code class="pattern">[\t\n\v\f\r ]</code> плюс несколько юникодных пробельных символов.</li>
</ul>
В квадратных скобках можно использовать и диапазоны и символьные классы -- вместе.
Например, нам нужно найти все слова в тексте. Если они на английском -- это достаточно просто:
```js
//+ run
var str = "The sun is rising!";
alert( str.match(/\w+/g) ); // The, sun, is, rising*!*
```
А если есть слова и на русском?
```js
//+ run
var str = "Солнце встаёт!";
alert( str.match(/\w+/g) ); // null*!*
```
Ничего не найдено! Это можно понять, ведь <code class="pattern">\w</code> -- это именно английская букво-цифра, как можно видеть из аналога <code class="pattern">[a-zA-Z0-9_]</code>.
Чтобы находило слово на русском -- нужно использовать диапазон, например <code class="pattern">/[а-я]/</code>.
А чтобы на обоих языках -- и то и другое вместе:
```js
//+ run
var str = "Солнце (the sun) встаёт!";
alert( str.match(/[\wа-я]+/gi) ); // Солнце, the, sun, вста, т*!*
```
...Присмотритесь внимательно к предыдущему примеру! Вы видите странность? Оно не находит букву <code class="match">ё</code>, более того -- считает её разрывом в слове. Причина -- в кодировке юникод, она подробно раскрыта в главе [](/string).
Буква `ё` лежит в стороне от основной кириллицы и её следует добавить в диапазон дополнительно, вот так:
```js
//+ run
var str = "Солнце (the sun) встаёт!";
alert( str.match(/[\wа-яё]+/gi) ); // Солнце, the, sun, встаёт*!*
```
Теперь всё в порядке.
## Диапазоны "кроме"
**Кроме обычных, существуют также *исключающие* диапазоны: <code class="pattern">[^…]</code>.**
Квадратные скобки, начинающиеся со знака каретки: <code class="pattern">[^…]</code> находят любой символ, *кроме указанных*.
Например:
<ul>
<li><code class="pattern">[^аеуо]</code> -- любой символ, кроме `'a'`, `'e'`, `'y'`, `'o'`.</li>
<li><code class="pattern">[^0-9]</code> -- любой символ, кроме цифры, то же что `\D`.</li>
<li><code class="pattern">[^\s]</code> -- любой не-пробельный символ, то же что `\S`.</li>
</ul>
Пример ниже ищет любые символы, кроме букв, цифр и пробелов:
```js
//+ run
alert( "alice15@gmail.com".match(/[^\d\sA-Z]/gi) ); // "@", "."
```
## Не нужно экранирование
Обычно, если мы хотим искать именно точку, а не любой символ, или именно символ `\`, то мы используем экранирование: указываем `\.` или `\\`.
В квадратных скобках большинство специальных символов можно использовать без экранирования, если конечно ни не имеют какой-то особый смысл именно внутри квадратных скобок.
То есть, "как есть", без экранирования можно использовать символы:
<ul>
<li>Точка <code class="pattern">'.'</code>.</li>
<li>Плюс <code class="pattern">'+'</code>.</li>
<li>Круглые скобки <code class="pattern">'( )'</code>.</li>
<li>Дефис <code class="pattern">'-'</code>, если он находится в начале или конце квадратных скобок, то есть не выделяет диапазон.</li>
<li>Символ каретки <code class="pattern">'^'</code>, если не находится в начале квадратных скобок.</li>
<li>А также открывающая квадратная скобка <code class="pattern">'['</code>.</li>
</ul>
То есть, точка `"."` в квадратных скобках означает не "любой символ", а обычную точку.
Регэксп <code class="pattern">[.,]</code> ищет один из символов "точка" или "запятая".
В примере ниже регэксп <code class="pattern">[-().^+]</code> ищет один из символов `-().^`. Они не экранированы:
```js
//+ run
// Без экранирования
var re = /[-().^+]/g;
alert( "1 + 2 - 3".match(re) ); // найдёт +, -
```
...Впрочем, даже если вы решите "на всякий случай" заэкранировать эти символы, поставив перед ними обратный слэш `\` -- вреда не будет:
```js
//+ run
// Всё заэкранировали
var re = /[\-\(\)\.\^\+]/g;
alert( "1 + 2 - 3".match(re) ); // тоже работает: +, -
```