Как найти определенный символ в тексте

Регулярные выражения (их еще называют regexp, или regex) — это механизм для поиска и замены текста. В строке, файле, нескольких файлах… Их используют разработчики в коде приложения, тестировщики в автотестах, да просто при работе в командной строке!

Чем это лучше простого поиска? Тем, что позволяет задать шаблон.

Например, на вход приходит дата рождения в формате ДД.ММ.ГГГГГ. Вам надо передать ее дальше, но уже в формате ГГГГ-ММ-ДД. Как это сделать с помощью простого поиска? Вы же не знаете заранее, какая именно дата будет.

А регулярное выражение позволяет задать шаблон «найди мне цифры в таком-то формате».

Для чего применяют регулярные выражения?

  1. Удалить все файлы, начинающиеся на test (чистим за собой тестовые данные)

  2. Найти все логи

  3. grep-нуть логи

  4. Найти все даты

А еще для замены — например, чтобы изменить формат всех дат в файле. Если дата одна, можно изменить вручную. А если их 200, проще написать регулярку и подменить автоматически. Тем более что регулярные выражения поддерживаются даже простым блокнотом (в Notepad++ они точно есть).

В этой статье я расскажу о том, как применять регулярные выражения для поиска и замены. Разберем все основные варианты.

Содержание

  1. Где пощупать

  2. Поиск текста

  3. Поиск любого символа

  4. Поиск по набору символов

  5. Перечисление вариантов

  6. Метасимволы

  7. Спецсимволы

  8. Квантификаторы (количество повторений)

  9. Позиция внутри строки

  10. Использование ссылки назад

  11. Просмотр вперед и назад

  12. Замена

  13. Статьи и книги по теме

  14. Итого

Где пощупать

Любое регулярное выражение из статьи вы можете сразу пощупать. Так будет понятнее, о чем речь в статье — вставили пример из статьи, потом поигрались сами, делая шаг влево, шаг вправо. Где тренироваться:

  1. Notepad++ (установить Search Mode → Regular expression)

  2. Regex101 (мой фаворит в онлайн вариантах)

  3. Myregexp

  4. Regexr

Инструменты есть, теперь начнём

Поиск текста

Самый простой вариант регэкспа. Работает как простой поиск — ищет точно такую же строку, как вы ввели.

Текст: Море, море, океан

Regex: море

Найдет: Море, море, океан

Выделение курсивом не поможет моментально ухватить суть, что именно нашел regex, а выделить цветом в статье я не могу. Атрибут BACKGROUND-COLOR не сработал, поэтому я буду дублировать регулярки текстом (чтобы можно было скопировать себе) и рисунком, чтобы показать, что именно regex нашел:

Обратите внимание, нашлось именно «море», а не первое «Море». Регулярные выражения регистрозависимые!

Хотя, конечно, есть варианты. В JavaScript можно указать дополнительный флажок i, чтобы не учитывать регистр при поиске. В блокноте (notepad++) тоже есть галка «Match case». Но учтите, что это не функция по умолчанию. И всегда стоит проверить, регистрозависимая ваша реализация поиска, или нет.

А что будет, если у нас несколько вхождений искомого слова?

Текст: Море, море, море, океан

Regex: море

Найдет: Море, море, море, океан

По умолчанию большинство механизмов обработки регэкспа вернет только первое вхождение. В JavaScript есть флаг g (global), с ним можно получить массив, содержащий все вхождения.

А что, если у нас искомое слово не само по себе, это часть слова? Регулярное выражение найдет его:

Текст: Море, 55мореон, океан

Regex: море

Найдет: Море, 55мореон, океан

Это поведение по умолчанию. Для поиска это даже хорошо. Вот, допустим, я помню, что недавно в чате коллега рассказывала какую-то историю про интересный баг в игре. Что-то там связанное с кораблем… Но что именно? Уже не помню. Как найти?

Если поиск работает только по точному совпадению, мне придется перебирать все падежи для слова «корабль». А если он работает по включению, я просто не буду писать окончание, и все равно найду нужный текст:

Regex: корабл

Найдет:

На корабле

И тут корабль

У корабля

Это статический, заранее заданный текст. Но его можно найти и без регулярок. Регулярные выражения особенно хороши, когда мы не знаем точно, что мы ищем. Мы знаем часть слова, или шаблон.

Поиск любого символа

. — найдет любой символ (один).

Текст:

Аня

Ася

Оля

Аля

Валя

Regex: А.я

Результат:

Аня

Ася

Оля

Аля

Валя

Символ «.» заменяет 1 любой символ

Символ «.» заменяет 1 любой символ

Точка найдет вообще любой символ, включая цифры, спецсисимволы, даже пробелы. Так что кроме нормальных имен, мы найдем и такие значения:

А6я

А&я

А я

Учтите это при поиске! Точка очень удобный символ, но в то же время очень опасный — если используете ее, обязательно тестируйте получившееся регулярное выражение. Найдет ли оно то, что нужно? А лишнее не найдет?

Точку точка тоже найдет!

Regex: file.

Найдет:

file.txt

file1.txt

file2.xls

Но что, если нам надо найти именно точку? Скажем, мы хотим найти все файлы с расширением txt и пишем такой шаблон:

Regex: .txt

Результат:

file.txt

log.txt

file.png

1txt.doc

one_txt.jpg

Да, txt файлы мы нашли, но помимо них еще и «мусорные» значения, у которых слово «txt» идет в середине слова. Чтобы отсечь лишнее, мы можем использовать позицию внутри строки (о ней мы поговорим чуть дальше).

Но если мы хотим найти именно точку, то нужно ее заэкранировать — то есть добавить перед ней обратный слеш:

Regex: .txt

Результат:

file.txt

log.txt

file.png

1txt.doc

one_txt.jpg

Также мы будем поступать со всеми спецсимволами. Хотим найти именно такой символ в тексте? Добавляем перед ним обратный слеш.

Правило поиска для точки:

. — любой символ

. — точка

Поиск по набору символов

Допустим, мы хотим найти имена «Алла», «Анна» в списке. Можно попробовать поиск через точку, но кроме нормальных имен, вернется всякая фигня:

Regex: А..а

Результат:

Анна

Алла

аоикА74арплт

Аркан

А^&а

Абба

Если же мы хотим именно Анну да Аллу, вместо точки нужно использовать диапазон допустимых значений. Ставим квадратные скобки, а внутри них перечисляем нужные символы:

Regex: А[нл][нл]а

Результат:

Анна

Алла

аоикА74арплт

Аркан

А^&а

Абба

Вот теперь результат уже лучше! Да, нам все еще может вернуться «Анла», но такие ошибки исправим чуть позже.

Как работают квадратные скобки? Внутри них мы указываем набор допустимых символов. Это может быть перечисление нужных букв, или указание диапазона:

[нл] — только «н» и «л»

[а-я] — все русские буквы в нижнем регистре от «а» до «я» (кроме «ё»)

[А-Я]    — все заглавные русские буквы

[А-Яа-яЁё]  — все русские буквы

[a-z]  — латиница мелким шрифтом

[a-zA-Z]  — все английские буквы

[0-9]  — любая цифра

[В-Ю]   — буквы от «В» до «Ю» (да, диапазон — это не только от А до Я)

[А-ГО-Р]   — буквы от «А» до «Г» и от «О» до «Р»

Обратите внимание — если мы перечисляем возможные варианты, мы не ставим между ними разделителей! Ни пробел, ни запятую — ничего.

[абв] — только «а», «б» или «в»

[а б в] — «а», «б», «в», или пробел (что может привести к нежелательному результату)

[а, б, в] — «а», «б», «в», пробел или запятая

Единственный допустимый разделитель — это дефис. Если система видит дефис внутри квадратных скобок — значит, это диапазон:

  • Символ до дефиса — начало диапазона

  • Символ после — конец

Один символ! Не два или десять, а один! Учтите это, если захотите написать что-то типа [1-31]. Нет, это не диапазон от 1 до 31, эта запись читается так:

  • Диапазон от 1 до 3

  • И число 1

Здесь отсутствие разделителей играет злую шутку с нашим сознанием. Ведь кажется, что мы написали диапазон от 1 до 31! Но нет. Поэтому, если вы пишете регулярные выражения, очень важно их тестировать. Не зря же мы тестировщики! Проверьте то, что написали! Особенно, если с помощью регулярного выражения вы пытаетесь что-то удалить =)) Как бы не удалили лишнее…

Указание диапазона вместо точки помогает отсеять заведомо плохие данные:

Regex: А.я или А[а-я]я

Результат для обоих:

Аня

Ася

Аля

Результат для «А.я»:

А6я

А&я

А я

^ внутри [] означает исключение:

[^0-9]  — любой символ, кроме цифр

[^ёЁ]  — любой символ, кроме буквы «ё»

[^а-в8]  — любой символ, кроме букв «а», «б», «в» и цифры 8

Например, мы хотим найти все txt файлы, кроме разбитых на кусочки — заканчивающихся на цифру:

Regex: [^0-9].txt

Результат:

file.txt

log.txt

file_1.txt

1.txt

Так как квадратные скобки являются спецсимволами, то их нельзя найти в тексте без экранирования:

Regex: fruits[0]

Найдет: fruits0

Не найдет: fruits[0]

Это регулярное выражение говорит «найди мне текст «fruits», а потом число 0». Квадратные скобки не экранированы — значит, внутри будет набор допустимых символов.

Если мы хотим найти именно 0-левой элемент массива фруктов, надо записать так:

Regex: fruits[0]

Найдет: fruits[0]

Не найдет: fruits0

А если мы хотим найти все элементы массива фруктов, мы внутри экранированных квадратных скобок ставим неэкранированные!

Regex: fruits[[0-9]]

Найдет:

fruits[0] = “апельсин”;

fruits[1] = “яблоко”;

fruits[2] = “лимон”;

Не найдет:

cat[0] = “чеширский кот”;

Конечно, «читать» такое регулярное выражение становится немного тяжело, столько разных символов написано…

Без паники! Если вы видите сложное регулярное выражение, то просто разберите его по частям. Помните про основу эффективного тайм-менеджмента? Слона надо есть по частям.

Допустим, после отпуска накопилась гора писем. Смотришь на нее и сразу впадаешь в уныние:

— Ууууууу, я это за день не закончу!

Проблема в том, что груз задачи мешает работать. Мы ведь понимаем, что это надолго. А большую задачу делать не хочется… Поэтому мы ее откладываем, беремся за задачи поменьше. В итоге да, день прошел, а мы не успели закончить.

А если не тратить время на размышления «сколько времени это у меня займет», а сосредоточиться на конкретной задаче (в данном случае — первом письме из стопки, потом втором…), то не успеете оглянуться, как уже всё разгребли!

Разберем по частям регулярное выражение — fruits[[0-9]]

Сначала идет просто текст — «fruits».

Потом обратный слеш. Ага, он что-то экранирует.

Что именно? Квадратную скобку. Значит, это просто квадратная скобка в моем тексте — «fruits[»

Дальше снова квадратная скобка. Она не экранирована — значит, это набор допустимых значений. Ищем закрывающую квадратную скобку.

Нашли. Наш набор: [0-9]. То есть любое число. Но одно. Там не может быть 10, 11 или 325, потому что квадратные скобки без квантификатора (о них мы поговорим чуть позже) заменяют ровно один символ.

Пока получается: fruits[«любое однозназначное число»

Дальше снова обратный слеш. То есть следующий за ним спецсимвол будет просто символом в моем тексте.

А следующий символ — ]

Получается выражение: fruits[«любое однозназначное число»]

Наше выражение найдет значения массива фруктов! Не только нулевое, но и первое, и пятое… Вплоть до девятого:

Regex: fruits[[0-9]]

Найдет:

fruits[0] = “апельсин”;

fruits[1] = “яблоко”;

fruits[9] = “лимон”;

Не найдет:

fruits[10] = “банан”;

fruits[325] = “ абрикос ”;

Как найти вообще все значения массива, см дальше, в разделе «квантификаторы».

А пока давайте посмотрим, как с помощью диапазонов можно найти все даты.

Какой у даты шаблон? Мы рассмотрим ДД.ММ.ГГГГ:

  • 2 цифры дня

  • точка

  • 2 цифры месяца

  • точка

  • 4 цифры года

Запишем в виде регулярного выражения: [0-9][0-9].[0-9][0-9].[0-9][0-9][0-9][0-9].

Напомню, что мы не можем записать диапазон [1-31]. Потому что это будет значить не «диапазон от 1 до 31», а «диапазон от 1 до 3, плюс число 1». Поэтому пишем шаблон для каждой цифры отдельно.

В принципе, такое выражение найдет нам даты среди другого текста. Но что, если с помощью регулярки мы проверяем введенную пользователем дату? Подойдет ли такой regexp?

Давайте его протестируем! Как насчет 8888 года или 99 месяца, а?

Regex: [0-9][0-9].[0-9][0-9].[0-9][0-9][0-9][0-9]

Найдет:

01.01.1999

05.08.2015

Тоже найдет:

08.08.8888

99.99.2000

Попробуем ограничить:

  • День месяца может быть максимум 31 — первая цифра [0-3]

  • Максимальный месяц 12 — первая цифра [01]

  • Год или 19.., или 20.. — первая цифра [12], а вторая [09]

Вот, уже лучше, явно плохие данные регулярка отсекла. Надо признать, она отсечет довольно много тестовых данных, ведь обычно, когда хотят именно сломать, то фигачат именно «9999» год или «99» месяц…

Однако если мы присмотримся внимательнее к регулярному выражению, то сможем найти в нем дыры:

Regex: [0-3][0-9].[0-1][0-9].[12][09][0-9][0-9]

Не найдет:

08.08.8888

99.99.2000

Но найдет:

33.01.2000

01.19.1999

05.06.2999

Мы не можем с помощью одного диапазона указать допустимые значения. Или мы потеряем 31 число, или пропустим 39. И если мы хотим сделать проверку даты, одних диапазонов будет мало. Нужна возможность перечислить варианты, о которой мы сейчас и поговорим.

Перечисление вариантов

Квадратные скобки [] помогают перечислить варианты для одного символа. Если же мы хотим перечислить слова, то лучше использовать вертикальную черту — |.

Regex: Оля|Олечка|Котик

Найдет:

Оля

Олечка

Котик

Не найдет:

Оленька

Котенка

Можно использовать вертикальную черту и для одного символа. Можно даже внутри слова — тогда вариативную букву берем в круглые скобки

Regex: А(н|л)я

Найдет:

Аня

Аля

Круглые скобки обозначают группу символов. В этой группе у нас или буква «н», или буква «л». Зачем нужны скобки? Показать, где начинается и заканчивается группа. Иначе вертикальная черта применится ко всем символам — мы будем искать или «Ан», или «ля»:

Regex: Ан|ля

Найдет:

Аня

Аля

Оля

Малюля

А если мы хотим именно «Аня» или «Аля», то перечисление используем только для второго символа. Для этого берем его в скобки.

Эти 2 варианта вернут одно и то же:

  • А(н|л)я

  • А[нл]я

Но для замены одной буквы лучше использовать [], так как сравнение с символьным классом выполняется проще, чем обработка группы с проверкой на все её возможные модификаторы.

Давайте вернемся к задаче «проверить введенную пользователем дату с помощью регулярных выражений». Мы пробовали записать для дня диапазон [0-3][0-9], но он пропускает значения 33, 35, 39… Это нехорошо!

Тогда распишем ТЗ подробнее. Та-а-а-ак… Если первая цифра:

  • 0 — вторая может от 1 до 9 (даты 00 быть не может)

  • 1, 2 — вторая может от 0 до 9

  • 3 — вторая только 0 или 1

Составим регулярные выражения на каждый пункт:

  • 0[1-9]

  • [12][0-9]

  • 3[01]

А теперь осталось их соединить в одно выражение! Получаем: 0[1-9]|[12][0-9]|3[01]

По аналогии разбираем месяц и год. Но это остается вам для домашнего задания =)

Потом, когда распишем регулярки отдельно для дня, месяца и года, собираем все вместе:

(<день>).(<месяц>).(<год>)

Обратите внимание — каждую часть регулярного выражения мы берем в скобки. Зачем? Чтобы показать системе, где заканчивается выбор. Вот смотрите, допустим, что для месяца и года у нас осталось выражение:

[0-1][0-9].[12][09][0-9][0-9]

Подставим то, что написали для дня:

0[1-9]|[12][0-9]|3[01].[0-1][0-9].[12][09][0-9][0-9]

Как читается это выражение?

  • ИЛИ   0[1-9]

  • ИЛИ   [12][0-9]

  • ИЛИ    3[01].[0-1][0-9].[12][09][0-9][0-9]

Видите проблему? Число «19» будет считаться корректной датой. Система не знает, что перебор вариантов | закончился на точке после дня. Чтобы она это поняла, нужно взять перебор в скобки. Как в математике, разделяем слагаемые.

Так что запомните — если перебор идет в середине слова, его надо взять в круглые скобки!

Regex: А(нн|лл|лин|нтонин)а

Найдет:

Анна

Алла

Алина

Антонина

Без скобок:

Regex: Анн|лл|лин|нтонина

Найдет:

Анна

Алла

Аннушка

Кукулинка

Итого, если мы хотим указать допустимые значения:

  • Одного символа — используем []

  • Нескольких символов или целого слова — используем |

Метасимволы

Если мы хотим найти число, то пишем диапазон [0-9].

Если букву, то [а-яА-ЯёЁa-zA-Z].

А есть ли другой способ?

Есть! В регулярных выражениях используются специальные метасимволы, которые заменяют собой конкретный диапазон значений:

Символ

Эквивалент

Пояснение

d

[0-9]

Цифровой символ

D

[^0-9]

Нецифровой символ

s

[ fnrtv]

Пробельный символ

S

[^ fnrtv]

Непробельный символ

w

[[:word:]]

Буквенный или цифровой символ или знак подчёркивания

W

[^[:word:]]

Любой символ, кроме буквенного или цифрового символа или знака подчёркивания

.

Вообще любой символ

Это самые распространенные символы, которые вы будете использовать чаще всего. Но давайте разберемся с колонкой «эквивалент». Для d все понятно — это просто некие числа. А что такое «пробельные символы»? В них входят:

Символ

Пояснение

Пробел

r

Возврат каретки (Carriage return, CR)

n

Перевод строки (Line feed, LF)

t

Табуляция (Tab)

v

Вертикальная табуляция (vertical tab)

f

Конец страницы (Form feed)

[b]

Возврат на 1 символ (Backspace)

Из них вы чаще всего будете использовать сам пробел и перевод строки — выражение «rn». Напишем текст в несколько строк:

Первая строка

Вторая строка

Для регулярного выражения это:

Первая строкаrnВторая строка

А вот что такое backspace в тексте? Как его можно увидеть вообще? Это же если написать символ и стереть его. В итоге символа нет! Неужели стирание хранится где-то в памяти? Но тогда это было бы ужасно, мы бы вообще ничего не смогли найти — откуда нам знать, сколько раз текст исправляли и в каких местах там теперь есть невидимый символ [b]?

Выдыхаем — этот символ не найдет все места исправления текста. Просто символ backspace — это ASCII символ, который может появляться в тексте (ASCII code 8, или 10 в octal). Вы можете «создать» его, написать в консоли браузера (там используется JavaScript):

console.log("abcbbdef");

Результат команды:

adef

Мы написали «abc», а потом стерли «b» и «с». В итоге пользователь в консоли их не видит, но они есть. Потому что мы прямо в коде прописали символ удаления текста. Не просто удалили текст, а прописали этот символ. Вот такой символ регулярное выражение  [b] и найдет.

См также:

What’s the use of the [b] backspace regex? — подробнее об этом символе

Но обычно, когда мы вводим s, мы имеем в виду пробел, табуляцию, или перенос строки.

Ок, с этими эквивалентами разобрались. А что значит [[:word:]]? Это один из способов заменить диапазон. Чтобы запомнить проще было, написали значения на английском, объединив символы в классы. Какие есть классы:

Класс символов

Пояснение

[[:alnum:]]

Буквы или цифры: [а-яА-ЯёЁa-zA-Z0-9]

[[:alpha:]]

Только буквы: [а-яА-ЯёЁa-zA-Z]

[[:digit:]]

Только цифры: [0-9]

[[:graph:]]

Только отображаемые символы (пробелы, служебные знаки и т. д. не учитываются)

[[:print:]]

Отображаемые символы и пробелы

[[:space:]]

Пробельные символы [ fnrtv]

[[:punct:]]

Знаки пунктуации: ! » # $ % & ‘ ( ) * + , -. / : ; < = > ? @ [ ] ^ _ ` { | }

[[:word:]]

Буквенный или цифровой символ или знак подчёркивания: [а-яА-ЯёЁa-zA-Z0-9_]

Теперь мы можем переписать регулярку для проверки даты, которая выберет лишь даты формата ДД.ММ.ГГГГГ, отсеяв при этом все остальное:

[0-9][0-9].[0-9][0-9].[0-9][0-9][0-9][0-9]

dd.dd.dddd

Согласитесь, через метасимволы запись посимпатичнее будет =))

Спецсимволы

Большинство символов в регулярном выражении представляют сами себя за исключением специальных символов:

[ ] / ^ $ . | ? * + ( ) { }

Эти символы нужны, чтобы обозначить диапазон допустимых значений или границу фразы, указать количество повторений, или сделать что-то еще. В разных типах регулярных выражений этот набор различается (см «разновидности регулярных выражений»).

Если вы хотите найти один из этих символов внутри вашего текста, его надо экранировать символом (обратная косая черта).

Regex: 2^2 = 4

Найдет: 2^2 = 4

Можно экранировать целую последовательность символов, заключив её между Q и E (но не во всех разновидностях).

Regex: Q{кто тут?}E

Найдет: {кто тут?}

Квантификаторы (количество повторений)

Усложняем задачу. Есть некий текст, нам нужно вычленить оттуда все email-адреса. Например:

  • test@mail.ru

  • olga31@gmail.com

  • pupsik_99@yandex.ru

Как составляется регулярное выражение? Нужно внимательно изучить данные, которые мы хотим получить на выходе, и составить по ним шаблон. В email два разделителя — собачка «@» и точка «.».

Запишем ТЗ для регулярного выражения:

  • Буквы / цифры / _

  • Потом @

  • Снова буквы / цифры / _

  • Точка

  • Буквы

Так, до собачки у нас явно идет метасимвол «w», туда попадет и просто текст (test), и цифры (olga31), и подчеркивание (pupsik_99). Но есть проблема — мы не знаем, сколько таких символов будет. Это при поиске даты все ясно — 2 цифры, 2 цифры, 4 цифры. А тут может быть как 2, так и 22 символа.

И тут на помощь приходят квантификаторы — так называют специальные символы в регулярных выражениях, которые указывают количество повторений текста.

Символ «+» означает «одно или более повторений», это как раз то, что нам надо! Получаем: w+@

После собачки и снова идет w, и снова от одного повторения. Получаем: w+@w+.

После точки обычно идут именно символы, но для простоты можно снова написано w. И снова несколько символов ждем, не зная точно сколько. Итого получилось выражение, которое найдет нам email любой длины:

Regex: w+@w+.w+

Найдет:

test@mail.ru

olga31@gmail.com

pupsik_99_and_slonik_33_and_mikky_87_and_kotik_28@yandex.megatron

Какие есть квантификаторы, кроме знака «+»?

Квантификатор

Число повторений

?

Ноль или одно

*

Ноль или более

+

Один или более

Символ * часто используют с точкой — когда нам неважно, какой идет текст до интересующей нас фразы, мы заменяем его на «.*» — любой символ ноль или более раз.

Regex: .*dd.dd.dddd.*

Найдет:

01.01.2000

Приходи на ДР 09.08.2015! Будет весело!

Но будьте осторожны! Если использовать «.*» повсеместно, можно получить много ложноположительных срабатываний:

Regex: .*@.*..*

Найдет:

test@mail.ru

olga31@gmail.com

pupsik_99@yandex.ru

Но также найдет:

@yandex.ru

test@.ru

test@mail.

Уж лучше w, и плюсик вместо звездочки.

А вот есть мы хотим найти все лог-файлы, которые нумеруются — log, log1, log2… log133, то * подойдет хорошо:

Regex: logd*.txt

Найдет:

log.txt

log1.txt

log2.txt

log3.txt

log33.txt

log133.txt

А знак вопроса (ноль или одно повторение) поможет нам найти людей с конкретной фамилией — причем всех, и мужчин, и женщин:

Regex: Назина?

Найдет:

Назин

Назина

Если мы хотим применить квантификатор к группе символов или нескольким словам, их нужно взять в скобки:

Regex: (Хихи)*(Хаха)*

Найдет:

ХихиХаха

ХихиХихиХихи

Хихи

Хаха

ХихиХихиХахаХахаХаха

(пустота — да, её такая регулярка тоже найдет)

Квантификаторы применяются к символу или группе в скобках, которые стоят перед ним.

А что, если мне нужно определенное количество повторений? Скажем, я хочу записать регулярное выражение для даты. Пока мы знаем только вариант «перечислить нужный метасимвол нужное количество раз» — dd.dd.dddd.

Ну ладно 2-4 раза повторение идет, а если 10? А если повторить надо фразу? Так и писать ее 10 раз? Не слишком удобно. А использовать * нельзя:

Regex: d*.d*.d*

Найдет:

.0.1999

05.08.20155555555555555

03444.025555.200077777777777777

Чтобы указать конкретное количество повторений, их надо записать внутри фигурных скобок:

Квантификатор

Число повторений

{n}

Ровно n раз

{m,n}

От m до n включительно

{m,}

Не менее m

{,n}

Не более n

Таким образом, для проверки даты можно использовать как перечисление d n раз, так и использование квантификатора:

dd.dd.dddd

d{2}.d{2}.d{4}

Обе записи будут валидны. Но вторая читается чуть проще — не надо самому считать повторения, просто смотрим на цифру.

Не забывайте — квантификатор применяется к последнему символу!

Regex: data{2}

Найдет: dataa

Не найдет: datadata

Или группе символов, если они взяты в круглые скобки:

Regex: (data){2}

Найдет: datadata

Не найдет: dataa

Так как фигурные скобки используются в качестве указания количества повторений, то, если вы ищете именно фигурную скобку в тексте, ее надо экранировать:

Regex: x{3}

Найдет: x{3}

Иногда квантификатор находит не совсем то, что нам нужно.

Regex: <.*>

Ожидание:

<req>
<query>Ан</query>
<gender>FEMALE</gender>

Реальность:

<req> <query>Ан</query> <gender>FEMALE</gender></req>

Мы хотим найти все теги HTML или XML по отдельности, а регулярное выражение возвращает целую строку, внутри которой есть несколько тегов.

Напомню, что в разных реализациях регулярные выражения могут работать немного по разному. Это одно из отличий — в некоторых реализациях квантификаторам соответствует максимально длинная строка из возможных. Такие квантификаторы называют жадными.

Если мы понимаем, что нашли не то, что хотели, можно пойти двумя путями:

  1. Учитывать символы, не соответствующие желаемому образцу

  2. Определить квантификатор как нежадный (ленивый, англ. lazy) — большинство реализаций позволяют это сделать, добавив после него знак вопроса.

Как учитывать символы? Для примера с тегами можно написать такое регулярное выражение:

<[^>]*>

Оно ищет открывающий тег, внутри которого все, что угодно, кроме закрывающегося тега «>», и только потом тег закрывается. Так мы не даем захватить лишнее. Но учтите, использование ленивых квантификаторов может повлечь за собой обратную проблему — когда выражению соответствует слишком короткая, в частности, пустая строка.

Жадный

Ленивый

*

*?

+

+?

{n,}

{n,}?

Есть еще и сверхжадная квантификация, также именуемая ревнивой. Но о ней почитайте в википедии =)

Позиция внутри строки

По умолчанию регулярные выражения ищут «по включению».

Regex: арка

Найдет:

арка

чарка

аркан

баварка

знахарка

Это не всегда то, что нам нужно. Иногда мы хотим найти конкретное слово.

Если мы ищем не одно слово, а некую строку, проблема решается в помощью пробелов:

Regex: Товар №d+ добавлен в корзину в dd:dd

Найдет: Товар №555 добавлен в корзину в 15:30

Не найдет: Товарный чек №555 добавлен в корзину в 15:30

Или так:

Regex: .* арка .*

Найдет: Триумфальная арка была…

Не найдет: Знахарка сегодня…

А что, если у нас не пробел рядом с искомым словом? Это может быть знак препинания: «И вот перед нами арка.», или «…арка:».

Если мы ищем конкретное слово, то можно использовать метасимвол b, обозначающий границу слова. Если поставить метасимвол с обоих концов слова, мы найдем именно это слово:

Regex: bаркаb

Найдет:

арка

Не найдет:

чарка

аркан

баварка

знахарка

Можно ограничить только спереди — «найди все слова, которые начинаются на такое-то значение»:

Regex: bарка

Найдет:

арка

аркан

Не найдет:

чарка

баварка

знахарка

Можно ограничить только сзади —  «найди все слова, которые заканчиваются на такое-то значение»:

Regex: аркаb

Найдет:

арка

чарка

баварка

знахарка

Не найдет:

аркан

Если использовать метасимвол B, он найдем нам НЕ-границу слова:

Regex: BакрB

Найдет:

закройка

Не найдет:

акр

акрил

Если мы хотим найти конкретную фразу, а не слово, то используем следующие спецсимволы:

^ — начало текста (строки)

$ — конец текста (строки)

Если использовать их, мы будем уверены, что в наш текст не закралось ничего лишнего:

Regex: ^Я нашел!$

Найдет:

Я нашел!

Не найдет:

Смотри! Я нашел!

Я нашел! Посмотри!

Итого метасимволы, обозначающие позицию строки:

Символ

Значение

b

граница слова

B

Не граница слова

^

начало текста (строки)

$

конец текста (строки)

Использование ссылки назад

Допустим, при тестировании приложения вы обнаружили забавный баг в тексте — дублирование предлога «на»: «Поздравляем! Вы прошли на на новый уровень». А потом решили проверить, есть ли в коде еще такие ошибки.

Разработчик предоставил файлик со всеми текстами. Как найти повторы? С помощью ссылки назад. Когда мы берем что-то в круглые скобки внутри регулярного выражения, мы создаем группу. Каждой группе присваивается номер, по которому к ней можно обратиться.

Regex: [ ]+(w+)[ ]+1

Текст: Поздравляем! Вы прошли на на новый уровень. Так что что улыбаемся и и машем.

Разберемся, что означает это регулярное выражение:

[ ]+ → один или несколько пробелов, так мы ограничиваем слово. В принципе, тут можно заменить на метасимвол b.

(w+) → любой буквенный или цифровой символ, или знак подчеркивания. Квантификатор «+» означает, что символ должен идти минимум один раз. А то, что мы взяли все это выражение в круглые скобки, говорит о том, что это группа. Зачем она нужна, мы пока не знаем, ведь рядом с ней нет квантификатора. Значит, не для повторения. Но в любом случае, найденный символ или слово — это группа 1.

[ ]+ → снова один или несколько пробелов.

1 → повторение группы 1. Это и есть ссылка назад. Так она записывается в JavaScript-е.

Важно: синтаксис ссылок назад очень зависит от реализации регулярных выражений.

ЯП

Как обозначается ссылка назад

JavaScript

vi

Perl

$

PHP

$matches[1]

Java

Python

group[1]

C#

match.Groups[1]

Visual Basic .NET

match.Groups(1)

Для чего еще нужна ссылка назад? Например, можно проверить верстку HTML, правильно ли ее составили? Верно ли, что открывающийся тег равен закрывающемуся?

Напишите выражение, которое найдет правильно написанные теги:

<h2>Заголовок 2-ого уровня</h2>
<h3>Заголовок 3-ого уровня</h3>

Но не найдет ошибки:

<h2>Заголовок 2-ого уровня</h3>

Просмотр вперед и назад

Еще может возникнуть необходимость найти какое-то место в тексте, но не включая найденное слово в выборку. Для этого мы «просматриваем» окружающий текст.

Представление

Вид просмотра

Пример

Соответствие

(?=шаблон)

Позитивный просмотр вперёд

Блюдо(?=11)

Блюдо1

Блюдо11

Блюдо113

Блюдо511

(?!шаблон)

Негативный просмотр вперёд (с отрицанием)

Блюдо(?!11)

Блюдо1

Блюдо11

Блюдо113

Блюдо511

(?<=шаблон)

Позитивный просмотр назад

(?<=Ольга )Назина

Ольга Назина

Анна Назина

(?шаблон)

Негативный просмотр назад (с отрицанием)

(см ниже на рисунке)

Ольга Назина

Анна Назина

Замена

Важная функция регулярных выражений — не только найти текст, но и заменить его на другой текст! Простейший вариант замены — слово на слово:

RegEx: Ольга

Замена: Макар

Текст был: Привет, Ольга!

Текст стал: Привет, Макар!

Но что, если у нас в исходном тексте может быть любое имя? Вот что пользователь ввел, то и сохранилось. А нам надо на Макара теперь заменить. Как сделать такую замену? Через знак доллара. Давайте разберемся с ним подробнее.

Знак доллара в замене — обращение к группе в поиске. Ставим знак доллара и номер группы. Группа — это то, что мы взяли в круглые скобки. Нумерация у групп начинается с 1.

RegEx: (Оля) + Маша

Замена: $1

Текст был: Оля + Маша

Текст стал: Оля

Мы искали фразу «Оля + Маша» (круглые скобки не экранированы, значит, в искомом тексте их быть не должно, это просто группа). А замнили ее на первую группу — то, что написано в первых круглых скобках, то есть текст «Оля».

Это работает и когда искомый текст находится внутри другого:

RegEx: (Оля) + Маша

Замена: $1

Текст был: Привет, Оля + Маша!

Текст стал: Привет, Оля!

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

RegEx: (Оля) + (Маша)

Замена: $2 — $1

Текст был: Оля + Маша

Текст стал: Маша — Оля

Теперь вернемся к нашей задаче — есть строка приветствия «Привет, кто-то там!», где может быть написано любое имя (даже просто числа вместо имени). Мы это имя хотим заменить на «Макар».

Нам надо оставить текст вокруг имени, поэтому берем его в скобки в регулярном выражении, составляя группы. И переиспользуем в замене:

RegEx: ^(Привет, ).*(!)$

Замена: $1Макар$2

Текст был (или или):

Привет, Ольга!

Привет, 777!

Текст стал:

Привет, Макар!

Давайте разберемся, как работает это регулярное выражение.

^ — начало строки.

Дальше скобка. Она не экранирована — значит, это группа. Группа 1. Поищем для нее закрывающую скобку и посмотрим, что входит в эту группу. Внутри группы текст «Привет, »

После группы идет выражение «.*» — ноль или больше повторений чего угодно. То есть вообще любой текст. Или пустота, она в регулярку тоже входит.

Потом снова открывающаяся скобка. Она не экранирована — ага, значит, это вторая группа. Что внутри? Внутри простой текст — «!».

И потом символ $ — конец строки.

Посмотрим, что у нас в замене.

$1 — значение группы 1. То есть текст «Привет, ».

Макар — просто текст. Обратите внимание, что мы или включает пробел после запятой в группу 1, или ставим его в замене после «$1», иначе на выходе получим «Привет,Макар».

$2 — значение группы 2, то есть текст «!»

Вот и всё!

А что, если нам надо переформатировать даты? Есть даты в формате ДД.ММ.ГГГГ, а нам нужно поменять формат на ГГГГ-ММ-ДД.

Регулярное выражение для поиска у нас уже есть — «d{2}.d{2}.d{4}». Осталось понять, как написать замену. Посмотрим внимательно на ТЗ:

ДД.ММ.ГГГГ

ГГГГ-ММ-ДД

По нему сразу понятно, что нам надо выделить три группы. Получается так: (d{2}).(d{2}).(d{4})

В результате у нас сначала идет год — это третья группа. Пишем: $3

Потом идет дефис, это просто текст: $3-

Потом идет месяц. Это вторая группа, то есть «$2». Получается: $3-$2

Потом снова дефис, просто текст: $3-$2-

И, наконец, день. Это первая группа, $1. Получается: $3-$2-$1

Вот и всё!

RegEx: (d{2}).(d{2}).(d{4})

Замена: $3-$2-$1

Текст был:

05.08.2015

01.01.1999

03.02.2000

Текст стал:

2015-08-05

1999-01-01

2000-02-03

Другой пример — я записываю в блокнот то, что успела сделать за цикл в 12 недель. Называется файлик «done», он очень мотивирует! Если просто вспоминать «что же я сделал?», вспоминается мало. А тут записал и любуешься списком.

Вот пример улучшалок по моему курсу для тестировщиков:

  1. Сделала сообщения для бота — чтобы при выкладке новых тем писал их в чат

  2. Фолкс — поправила статью «Расширенный поиск», убрала оттуда про пустой ввод при простом поиске, а то путал

  3. Обновила кусочек про эффект золушки (переписывала под ютуб)

И таких набирается штук 10-25. За один цикл. А за год сколько? Ух! Вроде небольшие улучшения, а набирается прилично.

Так вот, когда цикл заканчивается, я пишу в блог о своих успехах. Чтобы вставить список в блог, мне надо удалить нумерацию — тогда я сделаю ее силами блоггера и это будет смотреться симпатичнее.

Удаляю с помощью регулярного выражения:

RegEx: d+. (.*)

Замена: $1

Текст был:

1. Раз

2. Два

Текст стал:

Раз

Два

Можно было бы и вручную. Но для списка больше 5 элементов это дико скучно и уныло. А так нажал одну кнопочку в блокноте — и готово!

Так что регулярные выражения могут помочь даже при написании статьи =)

Статьи и книги по теме

Книги

Регулярные выражения 10 минут на урок. Бен Форта — Очень рекомендую! Прям шикарная книга, где все просто, доступно, понятно. Стоит 100 рублей, а пользы море.

Статьи

Вики — https://ru.wikipedia.org/wiki/Регулярные_выражения. Да, именно ее вы будете читать чаще всего. Я сама не помню наизусть все метасимволы. Поэтому, когда использую регулярки, гуглю их, википедия всегда в топе результатов. А сама статья хорошая, с табличками удобными.

Регулярные выражения для новичков — https://tproger.ru/articles/regexp-for-beginners/

Итого

Регулярные выражения — очень полезная вещь для тестировщика. Применений у них много, даже если вы не автоматизатор и не спешите им стать:

  1. Найти все нужные файлы в папке.

  2. Grep-нуть логи — отсечь все лишнее и найти только ту информацию, которая вам сейчас интересна.

  3. Проверить по базе, нет ли явно некорректных записей — не остались ли тестовые данные в продакшене? Не присылает ли смежная система какую-то фигню вместо нормальных данных?

  4. Проверить данные чужой системы, если она выгружает их в файл.

  5. Выверить файлик текстов для сайта — нет ли там дублирования слов?

  6. Подправить текст для статьи.

Если вы знаете, что в коде вашей программы есть регулярное выражение, вы можете его протестировать. Вы также можете использовать регулярки внутри ваших автотестов. Хотя тут стоит быть осторожным.

Не забывайте о шутке: «У разработчика была одна проблема и он стал решать ее с помощью регулярных выражений. Теперь у него две проблемы». Бывает и так, безусловно. Как и с любым другим кодом.

Поэтому, если вы пишете регулярку, обязательно ее протестируйте! Особенно, если вы ее пишете в паре с командой rm (удаление файлов в linux). Сначала проверьте, правильно ли отрабатывает поиск, а потом уже удаляйте то, что нашли.

Регулярное выражение может не найти то, что вы ожидали. Или найти что-то лишнее. Особенно если у вас идет цепочка регулярок. Думаете, это так легко — правильно написать регулярку? Попробуйте тогда решить задачку от Егора или вот эти кроссворды =)

PS — больше полезных статей ищите в моем блоге по метке «полезное». А полезные видео — на моем youtube-канале

В этом уроке вы научитесь выполнять простые операции поиска одного или нескольких символов.

Поиск заданного текста

Ben — регулярное выражение. Поскольку это просто текст, он ничем не напоминает регулярное выражение, но он им таки является! Регулярные выражения могут содержать простой текст (и могут даже состоять только из простого текста). По общему признанию, это полностью вырожденная обработка регулярных выражений, но это самый простой пример для начала.

Так, здесь идет:

Текст

Hello, my name is Ben. Please visit 
my website at http://www.forta.com/.

Регулярное выражение

Ben

Результат

Hello, my name is Ben. Please visit 
my website at http://www.forta.com/.

Используемое здесь регулярное выражение — буквальный текст, и оно находит вхождения Ben в первоначальный текст.

Давайте рассмотрим другой пример, используя тот же текст для поиска, но другое регулярное выражение:

Текст

Hello, my name is Ben. Please visit 
my website at http://www.forta.coin/.

Регулярное выражение

my

Результат

Hello, my name is Ben. Please visit 
my website at http://www.forta.com/.

my — также статический текст, но заметьте, что были найдены два вхождения my.

Сколько вхождений?

По умолчанию большинство механизмов обработки регулярных выражений возвращает только первое вхождение. В предыдущем примере обычно было бы найдено только первое вхождение my, но не второе.

Итак, почему было найдено два вхождения? В большинстве реализаций регулярных выражений предусмотрен механизм получения списка всех вхождений (обычно возвращаемых в массиве или в некотором другом специальном формате). В JavaScript, например, используя дополнительный флажок g (глобальный), можно получить массив, содержащий все вхождения.

Указание зависимости от регистра

Регулярные выражения чувствительны к регистру, так что Ben не будет соответствовать ben. Однако большинство реализаций регулярных выражений позволяет находить вхождения независимо от регистра. В JavaScript, например, можно указать дополнительный флажок i, чтобы при операциях поиска не учитывался регистр.

Поиск любого символа

Пока с помощью регулярных выражений мы находили статический (т.е. заранее заданный) текст. Теперь мы будем пытаться найти неизвестные символы.

Чтобы идентифицировать то, что разыскивается, в регулярных выражениях используются специальные символы или наборы символов. Символ . (точка) соответствует любому символу.

В операции поиска файлов в DOS эквивалентом регулярного выражения . является ?. В SQL эквивалентом регулярного выражения . является _ (символ подчеркивания).

Поэтому операция поиска c.t найдет cat и cot (и другие бессмысленные слова).

Вот пример:

Текст

sales1.xls 
orders3.xls 
sales2.xls 
sales3.xls 
apac1.xls 
europe2.xls 
na1.xls
na2.xls 
sa1.xls

Регулярное выражение

sales.

Результат

sales1.xls 
orders3.xls
sales2.xls
sales3.xls
apac1.xls 
europe2.xls 
na1.xls 
na2.xls 
sa1.xls

Здесь используется регулярное выражение sales. для того, чтобы найти все имена файлов, начинающихся с sales, за которым следует еще один символ. Три из этих девяти файлов соответствуют шаблону.

Часто термины шаблон, образец, модель обозначают регулярное выражение.

Заметьте, что регулярные выражения сопоставляют шаблоны строкам. Эти шаблоны не всегда будут совпадать со всей строкой, а только с теми символами, которые соответствуют шаблону, — даже если они являются только частью строки. В приведенном примере регулярное выражение не соответствовало имени файла; а соответствовало только части имени файла. Это различие важно помнить при передаче на обработку результатов, найденных с помощью регулярного выражения, некоторому другому коду или приложению.

Символ . соответствует любому символу — символу алфавита, цифре и даже самой .:

Текст

sales.xls
sales1.xls 
orders3.xls 
sales2.xls 
sales3.xls 
apac1.xls 
europe2.xls 
na1.xls
na2.xls 
sa1.xls

Регулярное выражение

sales.

Результат

sales.xls
sales1.xls 
orders3.xls
sales2.xls
sales3.xls
apac1.xls 
europe2.xls 
na1.xls 
na2.xls 
sa1.xls

Этот пример содержит один дополнительный файл, sales.xls. Файл был найден с помощью шаблона sales., поскольку . находит любой символ.

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

Рассмотрим другой пример, в котором используется тот же самый текст. На сей раз вы должны найти все файлы для Северной Америки (na) и Южной Америки (sa) независимо от того, какая цифра следует после этих сокращений:

Текст

sales1.xls 
orders3.xls 
sales2.xls 
sales3.xls 
apac1.xls 
europe2.xls 
na1.xls
na2.xls 
sa1.xls

Регулярное выражение

.a.

Результат

salesl.xls 
orders3.xls 
sales2.xls 
sales3.xls 
apac1.xls 
europe2.xls 
na1.xls
na2.xls 
sa1.xls

Регулярное выражение .а. действительно находит na1, na2 и sa1, но оно также нашло четыре других вхождения, которые не нужны. Почему? Потому что шаблон соответствует любым трем символам, средний из которых а.

Необходим шаблон, соответствующий .а., за которым следует точка. Вот еще одна попытка:

Текст

salesl.xls 
orders3.xls 
sales2.xls 
sales3.xls 
apac1.xls 
europe2.xls 
nal.xls
na2.xls 
sal.xls

Регулярное выражение

.a..

Результат

salesl.xls 
orders3.xls
sales2.xls
sales3.xls
apac1.xls 
europe2.xls 
nal.xls 
na2.xls 
sa1.xls

Шаблон .a.. работает нисколько не лучше, чем .а.; добавленная после а. точка соответствует любому следующему символу. Как же тогда найти точку, если специальный символ «точка» соответствует любому символу?

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

Точка . имеет специальное значение в регулярных выражениях. Если в шаблоне нужна точка ., должен быть способ указать в регулярном выражении, что имеется в виду фактический символ ., а не символ со специальным значением в регулярном выражении. Чтобы сделать это, предварите точку символом (наклонная черта влево). Наклонная черта влево — метасимвол (причудливый термин, обозначающий символ со специальным значением, в отличие от обычного символа). Поэтому точка . соответствует любому символу, а наклонная черта влево с точкой . соответствует только самому символу точка ..

Давайте снова попробуем выполнить предыдущий пример, на сей раз предваряя точку . наклонной чертой .:

Текст

salesl.xls 
orders3.xls 
sales2.xls 
sales3.xls 
apac1.xls 
europe2.xls 
nal.xls
na2.xls 
sal.xls

Регулярное выражение

.a..xls

Результат

salesl.xls 
orders3.xls
sales2.xls
sales3.xls
apac1.xls 
europe2.xls 
nal.xls
na2.xls
sa1.xls

С помощью шаблона .а..xls мы достигли цели. Первый символ . соответствует n (в первых двух вхождениях) или s (в третьем). Второй символ . соответствует 1 (в первом и третьем вхождениях) или 2 (во втором). Цепочка . соответствует точке ., отделяющей имя файла от расширения, ну a xls соответствует самому себе. (Фактически, соответствие работало бы и без xls; добавление в конец xls предотвратило нахождение имени файла вроде sa3.doc.)

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

О том, как применять специальные символы, вы узнаете из урока 4, «Использование метасимволов».

Если нужно найти наклонную черту влево (т.е. выполнить поиск ), используйте \ (две наклонных черты влево).

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

Резюме

Регулярные выражения, называемые также шаблонами, являются строками, составленными из символов. Эти символы могут быть литералами (фактический текст) или символами (специальные символы со специальными значениями), и в этом уроке вы узнали, как найти один с используя либо текст-литерал, либо метасимвол. Точка . ответствует любому символу. Наклонная черта влево пользуется для защиты символов и в качестве начального символа в последовательности специальных символов.

Каталог оборудования

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Производители

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Функциональные группы

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Занимался вот намедни всяческими

сексуальными

извращениями с текстами очередных аффтаров от медицины в MS Word. И нужно мне было искать и заменять кучу всякой нецензурщины и тарабарщины, ибо аффтары, по большей своей части, русскому языку

вовсе не

обучены плохо (всё на аглицком кириллицей норовят писать и прочее) и тексты форматировать читабельно не умеют. Заменять и просто менять там нужно было очень много чего, а стандартных общеизвестных встроенных в редактор средств поиска стало не хватать, нужно было прибегать к использованию регулярных выражений. А как? На известные мне ранее маски волшебная программа Word стала грязно ругаться матом. Как всегда выручил Гугл. Немного покопавшись я обнаружил, что гениальные мелкомягкие написатели MS Office и тут пошли своим путём, обозвав такие выражения wildcards и немного изменив их синтаксис. В целом разобраться можно.

Оказалось всё довольно просто (у меня Office 2007, но, думаю, будет справедливо и для предыдущих версий, разве что будут незначительные отличия в названиях пунктов, но вы разберётесь, я верю ;)). И не нужно было, по большому счёту, никуда лезть искать. Наряду со сразу видимыми, если вызвать в Word’е окно «Поиск» (Ctrl+F) или «Поиск и замена» (Ctrl+H), поставить курсор в поле «Найти» и нажать кнопочку «Больше», а после «Специальный», спецсимволами, есть и ещё одна опция, о которой чуть ниже.Оказалось всё довольно просто (у меня Office 2007, но, думаю, будет справедливо и для предыдущих версий, разве что будут незначительные отличия в названиях пунктов, но вы разберётесь, я верю ;)). И не нужно было, по большому счёту, никуда лезть искать. Наряду со сразу видимыми, если вызвать в Word’е окно «Поиск» (Ctrl+F) или «Поиск и замена» (Ctrl+H), поставить курсор в поле «Найти» и нажать кнопочку «Больше», а после «Специальный», спецсимволами, есть и ещё одна опция, о которой чуть ниже.
Сперва о стандартных масках поиска:

^? — любой знак
^# — любая цифра
^$ — любая буква
^p — Знак абзаца (¶) (если выбран параметр «Подстановочные знаки» следует заменить на ^13)
^t — знак табуляции (→) (если выбран параметр «Подстановочные знаки» следует заменить на ^9)
^+ — длинное тире ( — )
^= — короткое тире ( – )
^^ — знак крышки (^)
^l — принудительный разрыв строки (символ ↵ или 0xBF), такой бывает если нажать Shift+Enter (если выбран параметр «Подстановочные знаки» следует заменить на ^11)
^n — разрыв колонки (если выбран параметр «Подстановочные знаки» следует заменить на ^14)
^12 — Разрыв раздела или страницы (при замене добавляет разрыв страницы)
^m — Принудительный разрыв страницы (применяется также для поиска и замены разрывов разделов, если выбран параметр «Подстановочные знаки»)
^s — неразрывный пробел (º) (Ctrl+Shift+Space)
^~ — неразрывный дефис (≈)
^- — мягкий перенос (¬)
Теперь перейдём к полю «Заменить на», тут появляются две специфические опции:
^& — искомый текст
^c — содержимое буфера обмена
Как это можно использовать? Например так — пусть нужно найти текст «Achtung!» и «Achtung.»? покрасить его в зелёный и заменить на «Achtung, minen!» (именно красного цвета). Причём в тексте у вас есть и просто слово «achtung» с маленькой буквы, которое менять не нужно. Решение:
Написать красным «minen!» и вырезать в буфер обмена
Найти (отметив галочку «Учитывать регистр»): Achtung
Заменить на (переставить курсор на это поле и нажать кнопку «Формат», затем выбрать «Шрифт» и там зелёный):
Теперь Найти: Achtung^?
Заменить на: Achtung, ^c

С этим всё действительно просто и понятно. А если нужно в огромном списке литературы вида
Reynolds J. V., Murchan P., Leonard N. et al. High-dose interlenkin-2 promotes bacterial translocation from the gut // Brit. J. Cancer.-1995. -Vol. 72, N 3. — P. 634-636.
привести всё к нормальному виду
ReynoldsºJ.V., MurchanºP., LeonardºN. etºal. High-dose interlenkin-2 promotes bacterial translocation from the gut // Brit. J. Cancer.º— 1995.º— V.72(3).º— P.º634636.
Как быть? Ручками править в каждой строчке всё это будет очень долго и утомительно. Но это тоже можно сделать поиском и заменой.
Если отметить в окне поиска и замены галочку «Подстановочные знаки», то содержимое кнопки «Специальный» для поля «Найти» примет несколько иной вид:

? — любой знак
[ — ] — знак в диапазоне
< — в начале слова
> — в конце слова
() — диапазон
[!] — не
{; } — число вхождений
@ — предыдущий 1 или более
* — любое число знаков
А для поля «Заменить на» появится дополнительный пункт
n — искомое выражение
Как этим пользоваться? Просто. Начну почти по порядку.
? и * — по сути одно и то же, но выражение ??са будет для поиска значить «[пробел]оса», «коса», «лиса» и ещё кучу всего, содержащего два символа впереди «са». А выражение *са выделит вам весь текст от положения курсора в тексте до первого попавшегося «са», в том числе и «[курсор]По полю бежало животное с номером 25, это была лиса».
Близок по смыслу к предыдущим и символ @. Тут фантазии на пример у меня не хватило, заимствую у мелкомягких: lo@t поможет найти «lot» или «loot», ful@ поможет найти «ful» или «full» и т.д.  :)
Почти из той же оперы символы < и >: <ок поможет найти все «около», а ок> — всевозможный «шок».
Выражение [A-Z] поможет найти любую букву английского алфавита в верхнем регистре, а [A-я] — любую букву и русского и английского. Неразрывно с этим используется и выражение {; }. Выглядит это так: допустим, нужно найти все слова, начинающиеся с заглавной буквы и длиной от 4 до 5 букв и заканчивающиеся вопросительным знаком. Решением будет искать их по следующей маске:
[A-Я]{1;1}[a-я]{3;4}?
то есть найти одну заглавную букву и ещё 3 или 4 следующих за ней строчных плюс вопросительный знак. Тут есть одна маленькая тонкость — так как символ «?» используется как подстановочный, то, чтобы поиск его воспринял за знак вопроса, а не любой символ перед ним нужно поставить «». Если нужно найти сам символ «» в тексте, то это будет выглядеть как \, ну и т.д.
При помощи [!] можно найти например всё кроме заглавных букв: [!A-Я].
Теперь о самом наверное интересном операторе поиска — (). При его помощи можно находить несколько разных выражений и группировать их при помощи оператора n. Простой пример: пусть вам нужно по всему тексту заменить «Фамилия И О» на «И.О.ºФамилия». Решение:
Найти: ([A-Я]{1;1}[a-я]{2;11}) ([A-Я]{1;1}) ([A-Я]{1;1})
Заменить на: 2.3.^s1
То есть каждое выражение в скобках в поле «Найти» соответствует по порядку оператору n в поле «Заменить на».
Теперь с заданной выше задачей я думаю вы справитесь и сами ;)

P.S. Я желаю долгого здравия и личного счастья всем разработчикам «Визуального редактора» постов в ЖЖ. Пришлось копировать весь сгенерированный код в обычный блокнот и править всё ручками… Страницы, сгенерированные MS Word выглядят лучше чем ЭТО. Какое уж тут соблюдение стандартов HTML…

Регулярные выражения

Очень интересная тема, до которой у меня вечно не доходят руки. На практике почти не приходится использовать, но вещь безусловно полезная.

Для первого знакомства можно посмотреть видео Вебинар: Что такое регулярные выражения?

00:00 – 02:37 Вступление. Повестка и цели вебинара.
02:38 – 04:35 История возникновения регулярных выражений
04:36 – 10:54 Что такое регулярные выражения? Определение. Пример пасинга лога
10:55 – 14:37 Синтаксис регулярных выражений. Обычные (литералы) и специальные символы. Экранирование специальных символов.
14:38 – 17:09 Наборы символов (классы); [0-9], [Aa]
17:10 – 17:54 Специальные метасимволы-сокращения. d D s S w W
17:55 – 20:00 Указание позиции в поиске: начало и конец строки, начало и конец слова
20:01 – 20:24 Группировка a(bc|b|x)cc
20:25 – 27:30 Последовательности {m, n}. *, +, ?
27:32 – 30:29 Перебор “(a|c|z)”
30:30 – 34:07 Практические примеры. Как прочитать регулярное выражение?
34:07 – 35:59 Инструменты проверки регулярных выражений
36:00 – 42:19 Простые задачи, которые можно решить при помощи регулярных выражений: парсинг телефонных номеров, email, html тэгов
42:20 – 47:36 Примеры практического применения регулярных выражений. Найти все запущенные процессы по шаблону, все email адреса в файле.
47:37 – 50:33 Регулярные выражения в Notepad++ и Total Commander
50:34 – 56:59 Использование регулярных выражений в программировании: Python, Java, JavaScript
57:00 – 59:14 Применение регулярных выражений в автоматизации тестирования
59:15 – 1:01:31 Итоги.
1:01:32 – 1:09:45 Ответы на вопросы

Я для себя выписал на память кое-то в виде неупорядоченных записей.

Онлайн-сервисы

regexr.com

regexpal.com

Регулярные выражения — это язык поиска и манипуляций с подстроками в тексте. По сути это строка-образец, состоящая из символов и метасимволов и задающая правило поиска.

Порой сложно задать нужную строку для поиска. Склонения, окончания, регистр, изменяемая часть выражения и другие причины.

Удобно работать с большим текстом.

В http://regexr.com/ пишем онлайн регулярное выражение, и нам сразу показывается, где эти строки.


(WARN|ERROR)

Как вариант


^.*(WARN|ERROR).*((.*):(d=))$
$1 in class $2 in line $33

Просто этим строчками меняем текст логов в удобный текст.

Обычный текст ищем как есть.

Есть спецсимволы, например, @, который также доступен для поиска.

Экранирование

Есть специальные символы, которые используются в регулярных выражениях, поэтому их не получится искать. К ним относятся


)( ] [  ^ $ . | ? * +

Их следует экранировать, т.е. поставить обратный слеш ().

Для чего же он нужен? Рассмотрим простой пример. У нас есть строка с несколькими предложениями, в которых нам необходимо найти точки. Если вы попробуете это сделать, то будут выделены все символы. Дело в том, что точка является специальным метасимволом, которая заменяет любой символ в регулярном выражении, кроме переноса строки (см. ниже).

Нам следует указать, что точка в нашем случае должна быть не метасимволом, а обычным символом-точкой (.). Экранируя любой метасимвол, мы превращаем его в обычный символ. Это относится и к самому обратному слешу, для экранирования используем \.

Метасимвол точка

Точка заменяет любой символ в регулярном выражении. Если задать точку в регулярном выражении, то будут выделены все символы: буквы, цифры, пробел, точка, запятая и т.д. При этом точка совпадает с одним символом, но благодаря модификатору g поиск не ограничивается первым совпадением и продолжается дальше.

Создайте пример из трёх строк. Если мы добавим квантификатор + после точки (.+), то тем самым зададим поиск совпадающих символов от одного до бесконечности.

Обратите внимание, что регулярное выражение сообщит, что найдено три совпадения (по числу строк), а не количество всех символов, как это было бы без знака плюс.

Поскольку точка не совпадает с символом перевода строки, шаблон найдет совпадение до конца строки.

Мы знаем, что можно экранировать метасимвол точки, чтобы найти обычную точку.

Есть и другой способ — поместить точку в символьный класс, где она рассматривается как обычный символ: [.]+.

Использовать метасимвол точки полезно, когда есть строка с динамической составляющей, которая меняется. http://example.com/pictures/123/

Тогда для строки /pictures/123/, где числа 123 могут меняться, применим паттерн:


/pictures/.../

Мы экранировали слеши, ищем слово pictures, а также любые три символа (обязательно) после этого слова и слеша.

Наборы символов [Квадратные скобки]

Наборы символы позволяют задать определенные ограничения или диапазон. Например, если мы знаем, что будут выводиться только три цифры, то не обязательно использовать три точки, а можно сузить поиск. Для этого используются квадратные скобки, в которых указывается набор символов. Причем ищется только один символ.

Такой пример /pictures/[0-9]/ будет находить строку /pictures/1/ (с одним символом), но не найдет /pictures/123/

Можно указать буквы [a-z] — любой символ алфавита.

Символ ^ означает НЕ — [^ae]

Можно указывать не диапазон, а просто указать нужные символы. Например, [19] (напоминаю, только один символ)

Тогда /pictures/[19]/ найдет варианты /pictures/1/ и /pictures/9/

Есть готовые сокращения для диапазонов


9 [0-9] цифры
D [^d] не цифры
s [fnrtv] пробельный символ
S [^s] не пробельный символ
w [da-zA-Z_] буквенный символ
W [^w] не буквенный символ

Позиция

Если мы хотим найти какой-то конкретный текст, который заканчивается с определенным набором символов, то используется символ $


Рыжик - это кот.
Рыжик - это кот
кот по имени Рыжик.

Тогда выражение кот$ найдет слово только во второй строке. В первой в конце есть точка. В третьей слово начинается, а не заканчивается.

Для поиска строк, которые начинаются на определенное слово используется символ ^. Выражение ^кот найдет слово в третьей строке.

Символ b определяет границу слова, B — не границу слова.

Например, выражение [A-Z] будет находить все заглавные буквы. В том числе по два символа в словах TextView, StatusBar, EditText

Если использовать b[A-Z] то ищутся символы, которые является границей слова. Т.е. будет находить первые заглавные буквы в указанных словах. Соответственно, B[A-Z] наоборот найдет вторые заглавные буквы в этих словах.

Группировка (Круглые скобки)

Напомню, что круглые скобки являются метасимволами, поэтому их нужно экранировать, если вы ищете круглые скобки в тексе.

В основном удобна для замены. Допустим мы ищем какое-то слово. Помещаем его в круглые скобки, таким образом мы определили группу. Это простейший вариант.

Допустим, нас интересует слово gray. Можно просто написать это слово целиком в качестве шаблона. Однако слово gray часто пишут несколько как grey. Это также допустимый вариант.

Как же нам указать, что могут два варианта, которые нас интересуют? Вот здесь и пригодятся круглые скобки, которые произведут необходимую группировку.


gr(a|e)y

Мы можем таким образом создать несколько групп. При этом они нумеруются. Первая группа будет доступна в переменной под номером один — $1, вторая — $2 и т.д.

Создадим две группы. Теперь мы можем манипулировать этими группами. Для этого используем $1 и $2 для ссылки к этим группам. Тогда запись $2 $1 поменяет слова местами в тексте (режим Replace).

Для примера возьмём строку.


Кот, который гулял сам по себе

Регулярное выражение


(гулял) (сам по себе)

В режиме Replace пишем.


$2 $1

Теперь строка должна быть:


Кот, который сам по себе гулял

Можно использовать back reference, если мы знаем, что текст в группе повторяется. Тогда можно не писать (cat)(cat), а заменить на (back)1

Последовательности {Фигурные скобки}

Последовательности задаются фигурными скобками.

Если использовать [A-Z] то найдутся большие заглавные буквы, но один раз. А выражение [A-Z]{1,4} указывает, что нужно показать все повторяющиеся символы от 1 до 4 раз. Можно указать точное значение [A-Z]{3} — найдет слова, где идут именно три заглавные буквы подряд.

До четырех символов [A-Z]{,4}
От четырех символов [A-Z]{4,}

Существует сокращения для них *, +, ?

* — {0,} ноль или более символов
+ — {1,} один или более символов
? — {0,1} ноль или один символ

^.*слово$ — такое выражение найдет целую строку, которое заканчивается на слово.

Перебор

TExT|TEXT — найдет два варианта слова, которые написаны в разных регистрах. | — это или. Как вариант TE(x|X)T — третий символ мы определили в двух вариантах.

Читать регулярные выражения


([0-9]+)s.*s(dddd)$

В круглых скобках идет набор символов. В квадратных скобках идет набор цифр от 0 до 9, который может повториться один раз. Дальше пробел, бесконечное количество символов. Потом снова пробел. Потом идут четыре цифры подряд, которые обязательно являются концом строки. Например.


044 - 1234
asdf 123 asdf 1234

^[tT]eled$

Крышка — начало строки. Далее маленькая или большая буква T. Дальше три литерала. В конце строки должна быть цифра. Пример.


Tele2
tele1

([mM]y name is|I am)s[Mm]ykhailo [Pp]oliarush

Разные вариации


My name is Mykhailo Poliaruhs
I am mykailo Poliaruhs

Задачи

Телефонный номер 066.225-23-23

Три цифры, точка обязательно, три цифры, тире, две цифры, тире, две цифры.


[0-9]{3}.(d{2,3}|-)*

Как вариант, можно было написать


d{3}.d{3}-d{2}-d{2}

parse http: http://host.com/parameters


[htps]+://w{2,}.w+/w+

parse email


[email protected] w+@w+.w+

html tag


<a> <[^<]+?>

hexidecimal color #aabbcc


#?[0-9A-Fa-f]{6}

Применение

UNIX — найти запущенные процессы из папки bin.
Найти все email в тексте

Notepad++ (47.40)

Java (54.35)

Реклама

В этой статье рассматриваются различные методы поиска слова, символа или подстроки в тексте. Описываются преимущества и недостатки каждого метода.

  • Поиск символа в строке — использование strpos() для регистрозависимого поиска
  • Поиск символа в строке — использование функции stripos() для регистронезависимого поиска
  • Поиск символа в строке — использование регулярных выражений
  • Использование регулярных выражений для поиска точного вхождения слова
  • Использование strstr() для поиска подстроки

Простейшим способом проверить, содержит ли строка определённое слово, является использование PHP функции strpos(). Она возвращает позицию первого вхождения подстроки в строке или FALSE, если соответствия не найдены. Поэтому можно сравнить значение, возвращаемое функцией strpos() с FALSE, чтобы проверить наличие подстроки. Пример:

$the_string = "Я на 5 лет старше тебя.";
$the_word = "лет";
$the_character = "Я";
$the_substring = "5 лет";

// Вывод — Слово "лет" есть в данной строке.
if (strpos($the_string, $the_word) !== false) {
  echo 'Слово "'.$the_word.'" есть в данной строке.';
}

// Вывод — Символ "Я" есть в данной строке.
if (strpos($the_string, $the_character) !== false) {
  echo ' Символ "'.$the_character.'" есть в данной строке.';
}

// Вывод — Подстрока "5 лет" есть в данной строке.
if (strpos($the_string, $the_substring) !== false) {
  echo 'Подстрока "'.$the_substring.'" есть в данной строке.';
}

Обратите внимание, что я использовал оператор строгого неравенства (!==). Если искомое слово встречается в начале строки, функция strpos() вернёт 0. Это будет расценено оператором != как значение FALSE. Пример:

// Вывод — Символа "Я" нет в данной строке.
if (strpos($the_string, $the_character) != false) {
  echo 'Символ "'.$the_character.'" есть в данной строке.';
} else {
  echo 'Символа "'.$the_character.'" нет в данной строке.';
}

При поиске целого слова (например, “на”) функция также вернёт значение TRUE, если строка содержит такие слова, как “она”, “вена” или “например”.

Также можно использовать > -1 вместо !==. Потому что даже если strpos() вернёт 0 как значение индекса, он всё равно будет больше -1. Но помните, что оператор «больше» (>) работает медленнее оператора строгого неравенства (!==).

Для регистрозависимого поиска можно использовать функцию stripos(). Она работает аналогично функции strpos(). Единственное отличие заключается в том, что она игнорирует регистр при поиске подстроки внутри другой строки.

$the_string = "Ваня любит и яблоки, и апельсины.";
$the_word  = "ваня";
$the_character = "Я";
$the_substring = "ЛЮбИт И";

// Вывод — Слово "ваня" есть в данной строке.
if (stripos($the_string, $the_word) !== false) {
  echo 'Слово "'.$the_word.'" есть в данной строке.';
}

// Вывод — Символ "Я" есть в данной строке.
if (stripos($the_string, $the_character) !== false) {
  echo 'Символ "'.$the_character.'" есть в данной строке.';
}

// Вывод — Подстрока "ЛЮбИт И" есть в данной строке.
if (stripos($the_string, $the_substring) !== false) {
  echo 'Подстрока "'.$the_substring.'" есть в данной строке.';
}

Функция strpos() вернула бы значение FALSE во всех перечисленных выше случаях. Но функция stripos() проигнорировала регистр и вернула значение TRUE.

Другим способом поиска, независящим от регистра, является преобразование всех строк и подстрок в одинаковый регистр, используя функции strtolower() и strtoupper(). Для проверки можно использовать strpos(). Но проще stripos().

Также для поиска можно использовать регулярные выражения. Они лучше подходят для случаев, когда вы ищете в строке более сложные конструкции.

Но помните, что функция strpos() работает в три раза быстрее, чем регулярные выражения. Следующий пример демонстрирует, как с их помощью найти слово, символ в строке:

$the_string = "Я на 5 лет старше тебя.";
$the_word  = "лет";
$the_character = "Я";
$the_substring = "5 лет";

// Вывод — Слово "лет" есть в данной строке.
if (preg_match('/лет/', $the_string)) {
  echo 'Слово "'.$the_word.'" есть в данной строке.';
}

// Вывод — Символ "Я" есть в данной строке.
if (preg_match('/Я/', $the_string)) {
  echo 'Символ "'.$the_character.'" есть в данной строке.';
}

// Вывод — Подстрока "5 лет" есть в данной строке.
if (preg_match('/5 лет/', $the_string)) {
  echo 'Подстрока "'.$the_substring.'" есть в данной строке.';
}

Использование функции preg_match() имеет смысл только при сложном поиске. Например, для проверки того, содержит ли строка слова с десятью и более символами и т.п. Пример:

$the_string = 'Фотосинтез и рискованный – длинные слова.';

// Вывод — Данная строка содержит слова из 10 и более символов.
if (preg_match('/w{10,}/i', $the_string)) {
  echo 'Данная строка содержит слова из 10 и более символов.';
}

Чтобы сделать поиск регистронезависимым, добавьте флаг i в конец шаблона. Пример реализации:

$the_string = "Ваня любит и яблоки, и апельсины.";
$the_word  = "ваня";
$the_character = "Я";
$the_substring = "ЛЮбИт И";

// Вывод — Слово "ваня" есть в данной строке.
if (preg_match('/ваня/i', $the_string)) {
  echo 'Слово "'.$the_word.'" есть в данной строке.';
}

// Вывод — Символ "Я" есть в данной строке.
if (preg_match('/Я/i', $the_string)) {
  echo 'Символ "'.$the_character.'" есть в данной строке.';
}

// Вывод — Подстрока "ЛЮбИт И" есть в данной строке.
if (preg_match('/ЛЮбИт И/i', $the_string)) {
  echo 'Подстрока "'.$the_substring.'" есть в данной строке.';
}

Функции strpos() и stripos()работают быстрее, чем регулярные выражения. Но их использование для поиска точного вхождения слова может быть проблематичным.

В подобных ситуациях лучше применять регулярные выражения. Можно использовать выражение b в шаблоне регулярного выражения, чтобы обозначить границу слова. Если слово, которое вы ищете, заключено в выражения b, функция preg_match() найдёт только точные вхождения слова и вернет FALSE для частичных совпадений. Вот пример:

$the_string = 'Фотосинтез и рискованный – длинные слова.';
$the_word = 'синтез';

// Вывод — Слово "синтез" имеет точное совпадение в данной строке. [ЛОЖНО положительный]
if (preg_match('/синтез/', $the_string)) {
  echo 'Слово "синтез" имеет точное совпадение в данной строке. [ЛОЖНО положительный]';
}

// Вывод — Слово "синтез" имеет точное совпадение в данной строке. [ЛОЖНО положительный]
if (strpos($the_string, $the_word)) {
  echo 'Слово "синтез" имеет точное совпадение в данной строке. [ЛОЖНО положительный]';
}

// Вывод — Слово "синтез" не имеет точных совпадений в данной строке. [Ожидаемый Результат]
if (preg_match('/bсинтезb/', $the_string)) {
  echo 'Слово "синтез" имеет точное совпадение в данной строке. [ЛОЖНО положительный]';
} else {
  echo 'Слово "синтез" не имеет точных совпадений в данной строке. [Ожидаемый Результат]';
}

PHP функция strstr() может быть использована для проверки вхождения символа или подстроки. Она возвращает часть исходной строки, начиная с первого вхождения искомого слова и до конца. Функция вернёт значение FALSE, если подстрока не найдена. Благодаря этому можно проверить, содержит ли строка подстроку. Вот пример:

$the_string = "Я на 5 лет старше тебя.";
$the_word  = "лет";
$the_character = "Я";
$the_substring = "5 лет";

// Вывод — Слово "лет" есть в данной строке.
if (strstr($the_string, $the_word) !== false) {
  echo 'Слово "'.$the_word.'" есть в данной строке.';
}

// Вывод — Символ "Я" есть в данной строке.
if (strstr($the_string, $the_character) !== false) {
  echo 'Символ "'.$the_character.'" есть в данной строке.';
}

// Вывод — Подстрока "5 лет" есть в данной строке.
if (strstr($the_string, $the_substring) !== false) {
  echo 'Подстрока "'.$the_substring.'" есть в данной строке.';
}

Для регистронезависимого поиска используйте функцию stristr().

Краткое резюме

  1. Лучший метод поиска символа или слова в строке – PHP функции strpos(). Если нужно провести регистронезависимый поиск, применяйтеstripos(). Обе функции просты в использовании и работают быстрее остальных методов.
  2. Для сложного поиска используйте регулярные выражения. Вы также можете применять их для простого поиска, но они работают медленнее, чем функция strpos().
  3. Регулярные выражения полезны, когда вы ищете точное вхождение слова. Например, при поиске слова “сто” функция strpos() также вернёт значение TRUE, если строка содержит слово “Место”. С другой стороны, можно использовать выражение b в функции preg_match(), которая в таком случае возвратит FALSE.
  4. Используйте strstr() для регистрозависимого поиска и stristr() для регистронезависимого.

Понравилась статья? Поделить с друзьями:
  • Как составить предложение на болоте с буквой ц
  • Как исправить видеофайл если он не воспроизводится
  • Как найти точки на поверхности пирамиды
  • Как исправить ошибку в дискорде как то неловко получается
  • Как найти знаменатель гео прогрессии