Регулярные выражения
Содержание:
- Экранирование внутри […]
- Соответствие определенному набору символов
- Литерал регулярных выражений
- Опережающие и ретроспективные проверки — (?=) and (?
- Заключение
- Наборы и диапазоны
- JavaScript
- Создание строк
- Сложно, по полезно
- Создаем собственные регулярные выражения JavaScript
- Используем объект регулярного выражения
- Правила написания шаблонов в JavaScript
- Заметки о методах
- Флаги
- Заключение
- Как они работают?
- Обратные связи и именованные совпадения
- Жадность
- Точка и перенос строки
- Итого
Экранирование внутри […]
Обычно, когда мы хотим найти специальный символ, нам нужно экранировать его, например . А если нам нужна обратная косая черта, тогда используем , т.п.
В квадратных скобках большинство специальных символов можно использовать без экранирования:
- Символы не нужно экранировать никогда.
- Тире не надо экранировать в начале или в конце (где оно не задаёт диапазон).
- Символ каретки нужно экранировать только в начале (где он означает исключение).
- Закрывающую квадратную скобку , если нужен именно такой символ, экранировать нужно.
Другими словами, разрешены без экранирования все специальные символы, кроме случаев, когда они означают что-то особое в наборах.
Точка внутри квадратных скобок – просто точка. Шаблон будет искать один из символов: точку или запятую.
В приведённом ниже примере регулярное выражение ищет один из символов :
…Впрочем, если вы решите экранировать «на всякий случай», то не будет никакого вреда:
Соответствие определенному набору символов
Следующие спецсимволы используются для определения соответствия определенному набору символов.
\w – Соответствует буквенному или цифровому символу, а также знаку подчёркивания
\W – Соответствует любому символу, за исключением буквенного, цифрового и знака подчеркивания.
\d – Соответствует цифровому символу. Любые цифры от 0 до 9
\D – Соответствует не цифровому символу. Любые символы за исключением цифр от 0 до 9
\s – Соответствует пробельным символам. К ним относятся: пробел, табуляция и перевод строки
\S – Все символы за исключением пробельных
. – Соответствует любому символу за исключением перевода строки
– Обозначает диапазон символов. Например, выражение – соответствует символам “A”, “B”, “C”, “D” и “E”
– Соответствует перечисленным в символам в выражении. Например, – сработает только с символами “A”, “M” и “T”.
– Соответствует символам, не представленным в выражении. Например, с помощью найдутся все символы за исключением, “A”, “B”, “C”, “D” и “E”.
Литерал регулярных выражений
Второй способ — использование литерала. Как и конструктор, литерал регулярных выражений состоит из двух частей. Первая часть — это описываемый шаблон. Он заключается в слэши (). После закрывающего слэша идёт вторая часть — флаги. Они необязательны.
// Синтаксис литерала регулярных выражений/pattern/flags// Создание регулярного выражения// с помощью литерала// без флаговconst myPattern = //// Создание регулярного выражения// с помощью литерала// с одним флагомconst myPattern = //g
Примечание: два слэша в литерале регулярных выражений используются для того, чтобы заключить в них шаблон. Если ваш шаблон предполагает использование ещё одного или нескольких прямых слэшей, их необходимо экранировать обратным слэшем (), то есть
Опережающие и ретроспективные проверки — (?=) and (?
d(?=r) соответствует d, только если после этого следует r, но r не будет входить в соответствие выражения -> тест(?<=r)d соответствует d, только если перед этим есть r, но r не будет входить в соответствие выражения -> тест
Вы можете использовать оператор отрицания !
d(?!r) соответствует d, только если после этого нет r, но r не будет входить в соответствие выражения -> тест(?<!r)d соответствует d, только если перед этим нет r, но r не будет входить в соответствие выражения -> тест
Заключение
Как вы могли убедиться, области применения регулярных выражений разнообразны. Я уверен, что вы сталкивались с похожими задачами в своей работе (хотя бы с одной из них), например такими:
- Валидация данных (например, правильно ли заполнена строка time)
- Сбор данных (особенно веб-скрапинг, поиск страниц, содержащих определённый набор слов в определённом порядке)
- Обработка данных (преобразование сырых данных в нужный формат)
- Парсинг (например, достать все GET параметры из URL или текст внутри скобок)
- Замена строк (даже во время написания кода в IDE, можно, например преобразовать Java или C# класс в соответствующий JSON объект, заменить “;” на “,”, изменить размер букв, избегать объявление типа и т.д.)
- Подсветка синтаксиса, переименование файла, анализ пакетов и многие другие задачи, где нужно работать со строками (где данные не должны быть текстовыми).
Перевод статьи Jonny Fox: Regex tutorial — A quick cheatsheet by examples
Наборы и диапазоны
Наборы и диапазоны могут пригодиться, когда нужно указать специальные символы набора или их диапазон.
/* Набор или диапазон - Значение */ - любой один из символов в скобках. — любой символ, за исключением символов в скобках. - любой символ в диапазоне от "a" до "z". - любой символ не из диапазона от "a" до "z".(x) - "x", значение запоминается для дальнейшего использования.(?<name>x) - создание именованной скобочной группы, к которой можно обратиться по указанному имени.(?:x) - "x", значение не запоминается, поэтому совпадение невозможно извлечь из итогового массива элементов.
Примеры:
// - Любой один из символов в скобках.const myPattern = //console.log(myPattern.test('aei'))// true (есть a, e, i)console.log(myPattern.test('form'))// false (нет a, e или i)// - Любой символ, за исключением символов в скобках.const myPattern = //console.log(myPattern.test('aei'))// false (нет других символов, кроме a, e и i)console.log(myPattern.test('form'))// true (есть другие символы, кроме a, e и i)// - Любой символ в диапазоне от "a" до "z".const myPattern = //console.log(myPattern.test('bcd'))// true (есть символы в диапазоне от 'b' до 'g')console.log(myPattern.test('jklm'))// false (нет символов в диапазоне от 'b' до 'g')// - Любой символ не из диапазона от "a" до "z".const myPattern = //console.log(myPattern.test('bcd'))// false (нет других символов, кроме входящих в диапазон от 'b' до 'g')console.log(myPattern.test('jklm'))// true (есть другие символы, кроме входящих в диапазон от 'b' до 'g')// (x) - "x", значение запоминается для дальнейшего использования.const myPattern = /(na)da\1/console.log(myPattern.test('nadana'))// true - \1 запоминает и использует совпадение 'na' из первого выражения в скобках.console.log(myPattern.test('nada'))// false// (?<name>x) - Создание именованной скобочной группы, к которой можно обратиться по указанному имени.const myPattern = /(?<foo>is)/console.log(myPattern.test('Work is created.'))// trueconsole.log(myPattern.test('Just a text'))// false// (?:x) - "x", значение не запоминается.const myPattern = /(?:war)/console.log(myPattern.test('warsawwar'))// trueconsole.log(myPattern.test('arsaw'))// false
JavaScript
JS Array
concat()
constructor
copyWithin()
entries()
every()
fill()
filter()
find()
findIndex()
forEach()
from()
includes()
indexOf()
isArray()
join()
keys()
length
lastIndexOf()
map()
pop()
prototype
push()
reduce()
reduceRight()
reverse()
shift()
slice()
some()
sort()
splice()
toString()
unshift()
valueOf()
JS Boolean
constructor
prototype
toString()
valueOf()
JS Classes
constructor()
extends
static
super
JS Date
constructor
getDate()
getDay()
getFullYear()
getHours()
getMilliseconds()
getMinutes()
getMonth()
getSeconds()
getTime()
getTimezoneOffset()
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
now()
parse()
prototype
setDate()
setFullYear()
setHours()
setMilliseconds()
setMinutes()
setMonth()
setSeconds()
setTime()
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
toDateString()
toISOString()
toJSON()
toLocaleDateString()
toLocaleTimeString()
toLocaleString()
toString()
toTimeString()
toUTCString()
UTC()
valueOf()
JS Error
name
message
JS Global
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
Infinity
isFinite()
isNaN()
NaN
Number()
parseFloat()
parseInt()
String()
undefined
unescape()
JS JSON
parse()
stringify()
JS Math
abs()
acos()
acosh()
asin()
asinh()
atan()
atan2()
atanh()
cbrt()
ceil()
clz32()
cos()
cosh()
E
exp()
expm1()
floor()
fround()
LN2
LN10
log()
log10()
log1p()
log2()
LOG2E
LOG10E
max()
min()
PI
pow()
random()
round()
sign()
sin()
sqrt()
SQRT1_2
SQRT2
tan()
tanh()
trunc()
JS Number
constructor
isFinite()
isInteger()
isNaN()
isSafeInteger()
MAX_VALUE
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
prototype
toExponential()
toFixed()
toLocaleString()
toPrecision()
toString()
valueOf()
JS OperatorsJS RegExp
constructor
compile()
exec()
g
global
i
ignoreCase
lastIndex
m
multiline
n+
n*
n?
n{X}
n{X,Y}
n{X,}
n$
^n
?=n
?!n
source
test()
toString()
(x|y)
.
\w
\W
\d
\D
\s
\S
\b
\B
\0
\n
\f
\r
\t
\v
\xxx
\xdd
\uxxxx
JS Statements
break
class
continue
debugger
do…while
for
for…in
for…of
function
if…else
return
switch
throw
try…catch
var
while
JS String
charAt()
charCodeAt()
concat()
constructor
endsWith()
fromCharCode()
includes()
indexOf()
lastIndexOf()
length
localeCompare()
match()
prototype
repeat()
replace()
search()
slice()
split()
startsWith()
substr()
substring()
toLocaleLowerCase()
toLocaleUpperCase()
toLowerCase()
toString()
toUpperCase()
trim()
valueOf()
Создание строк
По сути, в JavaScript есть две категории строк: строковые примитивы и объекты String.
Примитивы
Строковые примитивы создаются следующими способами:
Почти во всех случаях вы должны использовать один из этих методов для создания новой строки.
При определении строкового литерала можно использовать одинарные кавычки (‘ ‘) или двойные кавычки (» «).
Объекты
Вы можете создать объект String, используя ключевое слово new.
Единственное реальное преимущество объекта перед строковым примитивом состоит в том, что вы можете назначить ему дополнительные свойства:
Однако очень мало случаев, когда это полезно. Практически во всех случаях следует создавать строковый примитив.
Сложно, по полезно
Новичкам регулярные выражения могут показаться абсолютной ерундой, а зачастую даже и профессиональным разработчикам, если не вкладывать время необходимое для их понимания.
Регулярные выражения сложно писать, сложно читать и сложно поддерживать/изменять.
Но иногда регулярные выражения это единственный разумный способ выполнить какие-то манипуляции над строками, поэтому они являются очень ценным инструментом.
Это руководство нацелено на то чтобы самым простым способом дать вам некоторое представление о регулярных выражениях в JavaScript и предоставить информацию о том как читать и создавать регулярные выражения.
Эмпирическое правило заключается в том, что простые регулярные выражения просты для чтения и записи, в то время как сложные регулярные выражения могут быстро превратиться в беспорядок, если вы не глубоко понимаете основы.
Создаем собственные регулярные выражения JavaScript
Существует два способа создания регулярного выражения: с использованием литерала регулярного выражения или с помощью конструктора регулярных выражений. Каждый из них представляет один и тот же шаблон: символ «c», за которым следует «a», а затем символ «t».
// литерал регулярного выражения заключается в слэши (/) var option1 = /cat/; // Конструктор регулярнго выражения var option2 = new RegExp("cat");
Как правило, если регулярное выражение остается константой, то есть не будет меняться, лучше использовать литерал регулярного выражения. Если оно будет меняться или зависит от других переменных, лучше использовать метод с конструктором.
Используем объект регулярного выражения
Создаем объект регулярного выражения
Этот объект описывает шаблон символов. Он используется для сопоставления шаблонов. Есть два способа сконструировать объект регулярного выражения.
Способ 1: используя литерал регулярного выражения, который состоит из шаблона, заключенного в слэши, например:
var reg = /ab+c/;
Литералы регулярных выражений запускают предварительную компиляцию регулярного выражения при анализе скрипта. Если регулярное выражение постоянно, то пользуйтесь им, чтобы увеличить производительность.
Способ 2: вызывая функцию-конструктор объекта RegExp, например:
var reg = new RegExp("ab+c");
Использование конструктора позволяет выполнить компиляцию регулярного выражения JS во время исполнения скрипта. Используйте данный способ, если регулярное выражение будет изменяться или не знаете шаблон заранее. Например, если вы получаете информацию от пользователя, который вводит поисковый запрос.
Методы объекта регулярного выражения
Давайте познакомимся с несколькими распространенными методами объекта регулярного выражения:
- compile() (устарел в версии 1.5) – компилирует регулярное выражение;
- exec() – производит сопоставление в строке. Возвращает первое совпадение;
- test() – производит сопоставление в строке. Возвращает значение true или false;
- toString() – возвращает строчное значение регулярного выражения.
Правила написания шаблонов в JavaScript
К самим выражением мы подойдем чуть позже, а пока разберем, что же под собой подразумевает такой параметр, как флаг.
Итак, flag – это инструмент для установки глобального или регистронезависимого поиска. В JS можно использовать четыре вида флага. При этом вы можете их прописывать как по отдельности, так и комбинировать в разном порядке и количестве. Хочу заметить, что от смены порядка результат выполнение не изменится.
Флаг | Предназначение |
m | Определяет многострочный поиск, т.е. образец сравнивается со всеми буквами, цифрами или другими знаками, которые разделены между собой известными пробельными символами. |
i | Поиск подстрок осуществляется без учета регистра. |
y | Выполнение проверки переменных начинается от символа, находящегося на позиции свойства под названием lastIndex. |
g | Задает глобальный поиск, после выполнения которого будут выведены все возможные совпадения. |
Ну а теперь давайте рассмотрим первый простой пример для понимания происходящего. С помощью переменной regExp я проверяю, есть ли вхождение в text слова «вариант». При этом я хочу, чтобы вывелись все случаи вхождения без учета регистра.
1 2 3 4 5 6 |
<script> var regExp = /вариант/gi; var text = "Вариант 1. напишите стих, состоящий из четырех строк. Вариант 2. Допишите стих из варианта 1."; var myArray = text.match(regExp ); alert(myArray); </script> |
Заметки о методах
Для работы с регулярными выражениями используется семь методов. Начнем разбор по порядку.
Search ()
Используется для нахождения позиции вхождения первого совпадения.
1 2 3 4 5 6 |
<script> var regExp = /рыб/gi; var text = "Покупайте речную рыбу!"; var myArray = text.search(regExp ); alert(myArray); //Ответ: 17 </script> |
Match ()
Работает в двух режимах в зависимости от того, укажете ли вы опциональный флаг g или нет.
1 2 3 4 5 6 7 8 |
<script> var regExp = /12.02/; var text = "11.02 - Концерт. 12.02 - Мастер-класс."; var myArray = text.match(regExp ); alert( myArray ); alert( myArray.input ); //11.02 - Концерт. 12.02 - Мастер-класс. alert( myArray.index ); //17 </script> |
Split ()
Как и в некоторых других языках программирования, метод Split () разбивает значение строковой переменной на подстроки по заданному разделителю.
1 2 3 4 |
<script> var text = "Пусть все будет хорошо"; alert(text.split(' ')); //Пусть,все,будет,хорошо </script> |
В качестве разделителя можно передавать как строковое значение, так и регэксп.
Replace ()
Очень удобный инструмент для нахождения и замены символов в задачах различной сложности. По умолчанию изменяет только первое совпавшее вхождение, однако это исправимо благодаря такой удобной штуке, как /g.
1 2 3 4 |
<script> var text = "Ты пробежал 3 км за 13 и 25 минут."; alert( text.replace( / и /g, "," )); // Ты пробежал 3 км за 13,25 минут </script> |
Exec ()
До этого все методы принадлежали к классу String. А оставшиеся два предоставляются классом RegExp.
Итак, текущий метод является дополнением к первым двум описанным методам. Он также ищет все вхождения и еще скобочные группы. Без указания флага g exec () работает, как match (). В противном случае совпадение запоминается, а его позиция записывается в lastIndex.
Последующий поиск продолжается с установленной позиции. Если далее совпадений больше не было, то lastIndex сбрасывается в 0.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<script> var str = 'Сорок сорок сидели на трубе'; var expresion = /сорок/ig; var res; alert( "lastIndex: " + expresion.lastIndex ); while (res = expresion.exec(str)) { alert( 'Найдено: ' + res + ' на позиции: ' + res.index ); alert( 'А теперь lastIndex равен: ' + expresion.lastIndex ); } alert( 'Под конец lastIndex сбрасывается в: ' + expresion.lastIndex ); </script> |
Test ()
Данный инструмент проверяет, а есть ли хоть один результат совпадения строк. Если есть, то возвращает булево значение true, иначе – false.
1 2 3 4 |
<script> var expresion = /крас/gi; alert( expresion.test("Ах, какая красна девица! красавица!")); //true </script> |
Вот я и рассказал вам основы такого механизма, как регулярные выражения. Для лучшего усвоения материала читайте и другие статьи на данную тематику на моем блоге, а также становитесь подписчиками и делитесь интересными ссылками с друзьями. Пока-пока!
Прочитано: 208 раз
Флаги
Флаги — последний тип символов, которые используются в регулярных выражениях. С помощью флагов можно легко расширить функционал шаблонов. К примеру, флаги позволяют игнорировать регистр букв, чтобы шаблон находил совпадения и в верхнем, и в нижнем регистрах, находить множественные совпадения и совпадения в многострочном тексте и т. д.
/* Флаг - Значение */g – Глобальный поиск, не останавливается после нахождения первого совпадения.i – Игнорирование регистра (соответствует верхнему и нижнему регистрам).s - Точка (.) соответствует переводу на новую строку.m – Многострочный ввод, начинается с "^" и заканчивается "$" (начало и конец каждой строки).
Примеры:
// флаг g - Глобальный поискconst myPattern = /xyz/gconsole.log(myPattern.test('One xyz and one more xyz'))// true// флаг i - Игнорирование регистраconst myPattern = /xyz/iconsole.log(myPattern.test('XyZ'))// true - регистр символов не имеет значения при нечувствительном к регистру поиске.// флаг s - Точка (.) соответствует переводу на новую строкуconst myPattern = /foo.bar/sconsole.log(myPattern.test('foo\nbar'))// trueconsole.log(myPattern.test('foo bar'))// trueconsole.log(myPattern.test('foobar'))// false
Заключение
Понимать и изучать регулярные выражения может быть непросто. Однако с помощью их короткого кода можно решать очень сложные задачи. И это определённо стоит стараний. Надеюсь, это руководство помогло вам разобраться в работе и способах применения регулярных выражений.
- Чистый код JavaScript — объекты и классы
- Хроники нового текстового редактора — от замысла до реализации
- Двоичное дерево поиска: вставка значения с использованием JavaScript
Читайте нас в телеграмме, vk и
Как они работают?
Регулярное выражение, которое мы определили выше как re1 , очень простое. Оно ищет строку hey без каки-либо ограничений: строка может содержать много текста, а слово hey находиться где-то в середине и регулярное выражение сработает. Строка может содержать только слово hey и регулярка опять сработает.
Это довольно просто.
Вы можете попробовать протестировать регулярное выражение с помощью метода RegExp.test(String) , который возвращает логическое ( boolean ) значение:
В примере выше мы просто проверили удовлетворяет ли «hey» шаблону регулярного выражения, который храниться в re1 .
Это проще простого, но вы уже знаете много о регулярных выражениях.
Обратные связи и именованные совпадения
Поддержка регулярных выражений в JavaScript неуклонно растет. Две из новых функций, которые будут реализованы, — обратные связи и именованные группы.
Одна из наиболее распространенных проблем, связанных с регулярными выражениями, — использование их для разбора таких языков, как XML. Попробуйте, например, определить теги и внутреннее содержимое элемента, где элемент начинается с тега, подобного следующему: , и заканчивается тем же тегом с . Если вы знаете имя элемента, о котором идет речь, задача довольно тривиальная, но если это не так, знайте, что на самом деле это невозможно сделать с помощью регулярных выражений, если движок не поддерживает обратные ссылки.
Обратная ссылка имеет вид , где равно 1,2,3 и т. д. и соответствует предыдущим группам захвата. Таким образом, чтобы захватить элемент и его содержимое, с помощью обратных ссылок можно сделать следующее:
Обратите внимание, что в этом случае два внешних элемента и были захвачены (и результаты группы могли быть получены функцией, выполняющей дополнительный анализ), а внутренние — нет. Почему? Поскольку после определения значения группы захвата регулярное выражение будет забирать все, пока не достигнет этого значения в закрывающем теге
Тем не менее, нетрудно понять, как того же результата можно достигнуть с использованием рекурсии:
Я оставляю написание процедуры для преобразования XML-структуры в JSON с использованием регулярных выражений в качестве упражнения для читателя.
Именованная группа позволяет ассоциировать определенную метку с группой захвата, а не просто использовать позиционный номер. Она принимает форму:
где — имя группы, а — содержимое группы захвата регулярного выражения. Например, вместо анализатора ссылок в квадратных скобках, обсуждавшегося ранее:
можете написать следующее:
где — именованная группа захвата «link», а — соответствующий шаблон замены.
Также стоит отметить, что если вы используете функцию (и не задействовали глобальный флаг), результирующий объект будет включать объект с именами групп захвата в качестве ключей:
Жадность
Это не совсем особенность, скорее фича, но все же достойная отдельного абзаца.
Все регулярные выражения в javascript – жадные. То есть, выражение старается отхватить как можно больший кусок строки.
Например, мы хотим заменить все открывающие тэги
На что и почему – не так важно
При запуске вы увидите, что заменяется не открывающий тэг, а вся ссылка, выражение матчит её от начала и до конца.
Это происходит из-за того, что точка-звёздочка в «жадном» режиме пытается захватить как можно больше, в нашем случае – это как раз до последнего .
Последний символ точка-звёздочка не захватывает, т.к. иначе не будет совпадения.
Как вариант решения используют квадратные скобки: :
Это работает. Но самым удобным вариантом является переключение точки-звёздочки в нежадный режим. Это осуществляется простым добавлением знака «» после звёздочки.
В нежадном режиме точка-звёздочка пустит поиск дальше сразу, как только нашла совпадение:
В некоторых языках программирования можно переключить жадность на уровне всего регулярного выражения, флагом.
В javascript это сделать нельзя… Вот такая особенность. А вопросительный знак после звёздочки рулит – честное слово.
Точка и перенос строки
Для поиска в многострочном режиме почти все модификации перловых регэкспов используют специальный multiline-флаг.
И javascript здесь не исключение.
Попробуем же сделать поиск и замену многострочного вхождения. Скажем, будем заменять на тэг подчеркивания: :
function bbtagit(text) { text = text.replace(/\(.*?)\[\/u\]/gim, '<u>$1</u>') return text } var line = "мой\n текст" alert( bbtagit(line) )
Попробуйте запустить. Заменяет? Как бы не так!
Дело в том, что в javascript мультилайн режим (флаг ) влияет только на символы ^ и $, которые начинают матчиться с началом и концом строки, а не всего текста.
Точка по-прежнему — любой символ, кроме новой строки. В javascript нет флага, который устанавливает мультилайн-режим для точки. Для того, чтобы заматчить совсем что угодно — используйте .
Работающий вариант:
function bbtagit(text) { text = text.replace(/\(*)\[\/u\]/gim, '<u>$1</u>') return text } var line = "мой\n текст" alert( bbtagit(line) )
Итого
Круглые скобки группируют вместе часть регулярного выражения, так что квантификатор применяется к ним в целом.
Скобочные группы нумеруются слева направо. Также им можно дать имя с помощью .
Часть совпадения, соответствующую скобочной группе, мы можем получить в результатах поиска.
- Метод возвращает скобочные группы только без флага .
- Метод возвращает скобочные группы всегда.
Если скобка не имеет имени, то содержимое группы будет по своему номеру в массиве-результате, если имеет, то также в свойстве .
Содержимое скобочной группы можно также использовать при замене : по номеру или по имени .
Можно исключить скобочную группу из запоминания, добавив в её начало . Это используется, если необходимо применить квантификатор ко всей группе, но не запоминать их содержимое в отдельном элементе массива-результата. Также мы не можем ссылаться на такие скобки в строке замены.