Как найти знак или символ

Искать символы Unicode обычно неудобно: приходится отвлекаться от основной работы. Программа SymbSearch упрощает этот процесс, задействуя горячие клавиши.

Как быстро найти символ Unicode

Unicode — это стандарт кодирования символов, который позволяет использовать знаки почти всех письменных языков. Если вы пользуетесь нестандартными его обозначениями, то неудобной таблице символов Windows и поиску в Google появилась неплохая альтернатива — SymbSearch. Это бесплатная утилита с открытым программным кодом, которая поможет быстро находить символы Unicode при помощи горячих клавиш, не отвлекаясь от рабочего процесса.

Программа пока не имеет инсталлятора. Чтобы установить её, достаточно разархивировать папку в нужном месте на жёстком диске. После этого запустите SymbSearch.exe, и SymbSearch окажется в фоновых процессах. Она занимает 105 МБ на жёстком диске и 64 МБ в оперативной памяти.

SymbSearch ориентирована на использование клавиатуры. Когда вы печатаете текст, нажмите Ctrl + Alt + W для запуска приложения. Найдите нужный символ, выберите его при помощи стрелок на клавиатуре и нажмите Enter. Значение будет скопировано в буфер обмена. Затем SymbSearch самостоятельно закроется, а вы вернётесь в активное окно текста, практически не оторвавшись от написания. Всё, что останется, — вставить символ при помощи сочетания клавиш Ctrl + V.

Изначальный список символов огромен, но не пугайтесь. SymbSearch фильтрует знаки по 11 категориям: греческий алфавит, латинский, математика, стрелки и другие. Чтобы быстро переключаться между категориями, используйте клавишу Alt.

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

Пользоваться мышью в программе неудобно. SymbSearch не понимает кликов. Чтобы скопировать символ, необходимо его выделить и нажать Ctrl + C.

Программа SymbSearch находится в активной разработке, но её уже можно использовать. Версия 0.4.0 пока не включает такой необходимой функции, как загрузка при запуске системы, поэтому придётся добавлять утилиту в автозагрузку вручную или запускать её каждый раз, когда это необходимо.

Разработчики SymbSearch отмечают, что в планах — поддержка Linux и macOS, настройка горячих клавиш, инсталлятор для программы и возможность автозагрузки.

Скачать SymbSearch →

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

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

1. Посетите сайт Symbols.com

Символы Com Поиск

Удачно названный Symbols.com — отличное место для начала поиска. Наряду с избранными подборками и категориями на главной странице, вы можете использовать поисковую систему по символам, чтобы найти то, что вы ищете. Просто введите запрос вверху, и вы увидите символы, которые ему соответствуют.

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

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

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

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

2. Нарисуйте символ, чтобы узнать его значение

Draw Shapecatcher

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

Одним из них является Shapecatcher . Просто нарисуйте символ, который хотите найти, с помощью мыши или сенсорного экрана и нажмите кнопку « Распознать» . Сервис вернет символы, соответствующие вашему рисунку.

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

3. Поиск символов с помощью Google

Google Symbol Search

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

В Chrome, наряду с большинством других браузеров, вы можете легко найти в Google любой текст. Просто выделите его на странице, щелкните правой кнопкой мыши и выберите « Поиск в Google» для «[term]» . Откроется новая вкладка с поиском в Google по этому термину. Если в вашем браузере по какой-то причине этого нет, вы можете просто скопировать символ, как любой другой текст, и вставить его в Google.

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

4. Просмотрите список символов

Сравнение списка символов Unicode

Unicode (стандарт для кодирования текста) поддерживает ряд общих символов, как они могут выглядеть как стандартный текст. Хотя они не имеют специальных клавиш на стандартной клавиатуре, вы можете использовать ALT-коды для ввода символов. вместо этого.

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

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

5. Изучите символы эмодзи

Руководство по смайликам

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

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

Если у вас все еще есть вопросы по поводу символов эмодзи, загляните в Emojipedia . Здесь вы можете искать определенные эмодзи, просматривать по категориям и читать новости эмодзи. Страница каждого смайлика рассказывает вам не только о его официальном значении, но и о том, для чего он часто используется.

6. Используйте инструмент поиска символов на бирже

MarketWatch Apple Stock

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

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

После того как вы попали на страницу компании, вы можете увидеть все виды данных, такие как тренды, новости и конкуренты.

Знание значения любого символа

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

У Facebook есть свой набор символов, которые вы можете не понять. Если это так, взгляните на наш справочник по многим символам

Теги: java, string, символ, поиск, строка, метод, буква, знак, contains

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

JavaPro_970x90-20219-3b63e7.png

Строкой в Java называют упорядоченную последовательность символов. Как правило строка в Java — это один из основных носителей текстовой информации.

Для работы со строками в Java применяют классы String, StringBuilder и StringBuffer. Класс String включает методы, возвращающие позицию символа либо подстроки в строке:
— indexOf() — для поиска с начала строки;
— lastIndexOf() — для выполнения поиска с конца строки.

Таким образом, если метод indexOf() найдёт заданную букву, символ либо строку, он вернёт индекс, то есть порядковый номер. Если не найдёт, будет возвращено -1. Также он позволяет искать символ или букву, начиная с указанного индекса.

Кроме того, стоит добавить, что класс String включает в себя ещё и метод contains, возвращающий true, когда в строке содержится заданная последовательность символов. Этот метод рекомендуется использовать лишь тогда, когда вам просто нужно узнать о существовании подстроки в строке, при этом позиция не имеет значения.

Метод indexOf()

Библиотека метода:


Синтаксис следующий:

public int indexOf(char ch)
public int indexOf(char ch, int fromIndex)

либо

public int indexOf(String s)
public int indexOf(String s, int fromIndex)

Соответственно, вызвать метод можно тоже несколькими способами:

int index = str1.indexOf(myChar);
int index = str1.indexOf(myChar, start);

или:

int index = str1.indexOf(myString);
int index = str1.indexOf(myString, start);

Представьте, что нам нужно отыскать в строке индекс первого вхождения требуемого символа/буквы, а также нужного слова. Как уже было сказано выше, метод indexOf() вернёт нам индекс первого вхождения, а в случае неудачи — вернёт -1.

JavaSpec_970x90-20219-e8e90f.png

Посмотрите на следующий код:

public class Main {
   public static void main(String[] args) {
      String str = "Otus — онлайн-образование";

      int indexM = str.indexOf("з"); // Ищем символ в строке
      int indexJava = str.indexOf("онлайн"); // Ищем слово в строке

      if(indexM == - 1) {
         System.out.println("Символ "з" не найден.");
      } else {
         System.out.println("Символ "з" найден, его индекс: " + indexM);
      }

      if(indexJava == - 1) {
         System.out.println("Слово "онлайн" не найдено.");
      } else {
         System.out.println("Слово "онлайн" найдено, его индекс: " + indexJava);
      }
   }
}

Результат получим следующий:

Символ "з" найден, его индекс: 18
Слово "онлайн" найдено, его индекс: 7

Метод contains

Бывают ситуации, когда нам необходимо проверить, содержит ли наша строка конкретный символ/букву либо слово. Нижеследующий Java-код продемонстрирует и этот пример:

public class Main {
   public static void main(String[] args) {
      String str = "Otus — онлайн-образование";
      System.out.println("Слово "Otus" есть в строке str? Ответ: " + str.contains("Otus"));
      System.out.println("Символ "z" присутствует в строке str? Ответ: " + str.contains("z"));
   }
}

В этом случае результат будет следующим:

Слово "Otus" есть в строке str? Ответ: true
Символ "z" присутствует в строке str? Ответ: false

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

JavaPro_970x550-20219-8420e5.png

Метасимволы были введены в уроке 2, «Поиск отдельных символов». В этом уроке вы узнаете о дополнительных метасимволах, используемых для указания соответствия с определенными символами или типами символов.

Символ : новые встречи со старым знакомым

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

Метасимволы — символы, которые имеют специальное значение в регулярных выражениях. Точка . является метасимволом, который соответствует любому отдельному символу (как объяснялось в уроке 2, «Поиск отдельных символов»). Точно так же левая скобка ([) — метасимвол, который отмечает начало набора (см. урок 3, «Соответствие набору символов»).

Поскольку метасимволы имеют специальное значение в регулярных выражениях, эти символы не могут использоваться для нахождения соответствующих им литералов. Например, вы не можете использовать [, чтобы найти [; точно так же вы не найдете точку . с помощью точки .. Рассмотрим следующий пример. Регулярное выражение используется, чтобы в программе на JavaScript попытаться найти выражение с массивом, содержащее [ и ]:

Текст

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

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

myArray[0]

Результат

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

В этом примере блок текста — фрагмент кода на JavaScript. Регулярное выражение — то, что вы, вероятно, использовали бы в текстовом редакторе. Подразумевается, что оно должно было бы соответствовать буквальному тексту myArray[0], но это не так. Почему не так? В регулярном выражении метасимволы [ и ] используются для того, чтобы определить набор символов (но не сами символы [ и ]), Поэтому шаблону myArray[0] соответствует текст myArray, за которым следует один из членов набора, а 0 — единственный член. Так что myArray[0] соответствует только myArray0.

Как объяснялось в уроке 2, «Поиск отдельных символов», метасимволы можно защитить наклонной чертой влево. Поэтому . соответствует ., а [ соответствует [. Каждый метасимвол можно защитить предшествующей ему наклонной чертой влево; защищенный символ соответствует самому себе, а не специальному значению метасимвола. Чтобы на самом деле найти [ и ], эти символы нужно защитить. Далее снова рассмотрим тот же самый пример, на сей раз с защищенными метасимволами:

Текст

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

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

myArray[0]

Результат

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

Поиск работал правильно. [ соответствует [, a ] соответствует ]; так что myArray[0] соответствует myArray[0].

Честно говоря, использовать в этом примере регулярное выражение было не особенно необходимо — проще было обойтись поиском буквального текста. Но вообразите, что нужно было бы найти не только myArray[0], но и myArray[1], myArray[2] и т.д. Тогда был бы смысл использовать именно регулярное выражение. Нужно было бы защитить [ и ] и определить символы, которые могли бы встретиться между квадратными скобками. Если бы нужно было найти элементы массива с индексами от 0 до 9, можно было бы использовать следующее регулярное выражение:

myArray[[0-9]]

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

Метасимволы, которые являются частью пары (например, [ или ]), нужно защитить, если они не используются как метасимволы, в противном случае синтаксический анализатор регулярных выражений может сгенерировать сообщение об ошибке.

Наклонная черта влево используется для защиты метасимволов. Это означает, что сама по себе наклонная черта влево рассматривается как метасимвол; она используется для защиты других символов. Как отмечено в уроке 2, «Поиск отдельных символов», чтобы закодировать наклонную черту , нужно саму ее защитить, т.е. указать ее как \.

Рассмотрим следующий простой пример. Текст — путь к файлу, в котором используются наклонные черты влево (так принято в DOS и Windows). Теперь вообразите, что этот путь нужно использовать в системе Linux или Unix, и потому вы должны определить местонахождение всех наклонных черт влево для того, чтобы заменить их на наклонные черты вправо:

Текст

homebensales

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

\

Результат

homebensales

Выражение \ соответствует , и потому найдены четыре совпадения. Если бы вы определили как регулярное выражение, вполне вероятно, что было бы сгенерировано сообщение об ошибке. (Скорее всего, это произошло бы потому, что синтаксический анализатор регулярных выражений законно предположил бы, что выражение не закончено; ведь, в конце концов, в регулярном выражении после всегда следует другой символ.)

Поиск пробельных символов

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

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

Таблица 4.1. Метасимволы, обозначающие пробельные символы

Метасимвол Описание метасимвола
[b] Возврат на один символ (Backspace)
f Перевод страницы (Form feed)
n Перевод строки (Line feed)
r Перевод каретки (Carriage return, CR)
t Табуляция (Tab)
v Вертикальная табуляция (Vertical tab)

Следующий блок текста содержит ряд записей в формате с разделителями-запятыми (часто этот формат называется CSV). Перед обработкой записей из данных нужно удалить все пустые строки. Вот пример:

Текст

"101","Ben","Forta" 
"102","Jim","James"

"103","Roberta","Robertson"
"104","Bob","Bobson"

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

rnrn

Результат

"101","Ben","Forta" 
"102","Jim","James" 
 
"103","Roberta","Robertson"
"104","Bob","Bobson"

Выражение rn соответствует комбинации перевода строки с переводом каретки, используемой (в Windows) как маркер конца строки. Поэтому rnrn соответствует двум маркерам конца строки, т.е. пустой строке между двумя записями.

В Windows в качестве маркера конца строки используется rn, однако в системе Unix (и Linux) применяется только символ перевода строки. В этих системах нужно будет использовать только n (без r). Идеальное регулярное выражение, вероятно, должно учитывать оба случая и потому должно содержать необязательный символ r и требуемый n. Поэтому в следующем уроке этот пример придется рассмотреть повторно.

Чаще всего используются метасимволы r и n, а также t (табуляция). Другие пробельные символы обычно применяются редко.

Вы только что познакомились с двумя разновидностями метасимволов. Точка . и открывающая квадратная скобка [ — метасимволы, если они не защищены. Символы f и n, например, являются метасимволами только тогда, когда они защищены. Если они не защищены, то они — буквальные символы, которые соответствуют только самим себе.

Поиск символов определенных типов

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

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

Поиск цифр (и нецифровых символов)

Как вы уже знаете из урока 3, «Соответствие набору символов», [0-9] — сокращение для [0123456789]; оно используется для поиска любой цифры. Чтобы найти что-нибудь отличное от цифры, этот набор может быть инвертирован: [^0-9]. В табл. 4.2 перечислены сокращения для класса цифр и класса нецифровых символов.

Таблица 4.2. Метасимволы цифр

Метасимвол Описание метасимвола
d Любая цифра (digit) (то же самое, что и [0-9])
D Любой нецифровой символ (то же самое, что и [^0-9])

Чтобы продемонстрировать использование этих метасим волов, давайте повторно рассмотрим предыдущий пример:

Текст

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

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

myArray[d]

Результат

var myArray = new Array();
...
if (myArray[0] == 0) {
...
}

Выражение [ соответствует [, d соответствует любой от дельной цифре, а ] соответствует ], так что myArray[d] соответствует myArray[0]. myArray[d] — сокращение для myArray[[0-9]], которое в свою очередь является сокращением для myArray[[0123456789]]. Это регулярное выражение также найдет myArray[1], myArray[2], и т.д. (но не найдет myArray[10]).

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

Синтаксис регулярных выражений чувствителен к регистру. Метасимвол d соответствует цифрам, a D — полная противоположность d. To же самое истинно для метасимволов других классов.

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

Поиск алфавитно-цифровых символов (и символов, не относящихся к алфавитно-цифровым)

Есть еще один часто используемый набор — все алфавитно-цифровые символы, т.е. символы от А до z (А на верхнем регистре и z на нижнем регистре), цифры, символ подчеркивания (часто используемый в именах файлов и папок, именах переменных в приложениях, именах объектов баз данных и в других случаях). В табл. 4.3 перечислены сокращения для класса алфавитно-цифровых символов и символов, не относящихся к алфавитно-цифровым.

Следующий пример — выборка из базы данных, содержащей записи с американскими почтовыми индексами и канадскими почтовыми кодами:

Текст

11213 
А1С2ЕЗ 
48075 
48237
M1B4F2
90046
Н1Н2Н2

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

wdwdwd

Результат

11213 
А1С2Е3 
48075 
48237
M1B4F2
90046
Н1Н2Н2

Чтобы отыскать только канадские почтовые коды, шаблон содержит комбинацию метасимволов w и d.

Таблица 4.3. Метасимволы для алфавитно-цифровых символов

Метасимвол Описание метасимвола
w Любой алфавитно-цифровой символ на верхнем или нижнем регистре и символ подчеркивания (то же самое, что и [a-zA-Z0-9_])
W Любой символ, отличный от символа подчеркивания и не относящийся к алфавитно-цифровым (то же самое, что и [^a-zA-Z0-9_])

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

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

Поиск пробельных символов и символов, не относящихся к ним

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

Таблица 4.4. Метасимволы для класса всех пробельных символов

Метасимвол Описание метасимвола
s Любой пробельный символ (то же самое, что и [fnrtv])
S Любой непробельный символ (то же самое, что и [^fnrtv])

Обратите внимание, что метасимвол возврата на один символ, [b], не включен в s и не исключается применением S.

Указание шестнадцатеричных и восьмеричных значений

Хотя определять символ его восьмеричным или шестнадцатеричным значением не рекомендуется, стоит отметить, что это в принципе возможно.

Указание шестнадцатеричных значений

Чтобы указать шестнадцатеричное (т.е. по основанию 16) значение, перед ним нужно написать х. Поэтому х0А (символ с ASCII-кодом 10, символ перевода строки) функционально эквивалентен n.

Указание восьмеричных значений

Чтобы указать восьмеричное (т.е. по основанию 8) двух- или трехзначное значение, перед ним нужно написать . Поэтому 11 (символ с ASCII-кодом 9, символ табуляции) функционально эквивалентен t.

Во многих реализациях регулярных выражений допускается также спецификация управляющих символов с помощью c. Например, cZ соответствует Ctrl-Z. На практике этот синтаксис используется очень редко.

Использование символьных классов POSIX

Урок по метасимволам и сокращениям для различных наборов символов не был бы полным без упоминания о символьных классах POSIX (табл. 4.5). Они — еще одна форма сокращения, которое поддерживается многими (но не всеми) реализациями регулярных выражений.

JavaScript не поддерживает символьные классы POSIX в регулярных выражениях.

Таблица 4.5. Символьные классы POSIX

Класс Описание класса
[:alnum:] Любой символ или цифра (то же самое, что и [a-zA-Z0-9])
[:alpha:] Любой символ (то же самое, что и [a-zA-Z])
[:blank:] Пробел или табуляция (то же самое, что и [t ])
[:cntrl:] Управляющие символы ASCII (ASCII-коды от 0 до 31 и 127)
[:digit:] Любая цифра (то же самое, что и [0-9])
[:graph:] То же самое, что и [:print:], но пробел исключен
[:lower:] Любой символ нижнего регистра (то же самое, что и [a-z])
[:print:] Любой печатаемый символ
[:punct:] Любой символ, который не входит ни в [:alnum:], ни в [:cntrl:]
[:space:] Любой пробельный символ, включая пробел (то же самое, что и [fnrtv ])
[:upper:] Любая прописная буква (то же самое, что и [А-Z])
[:xdigit:] Любая шестнадцатеричная цифра (то же самое, что и [a-fA-F0-9])

Синтаксис POSIX весьма отличается от синтаксиса ранее изученных метасимволов. Чтобы продемонстрировать использование классов POSIX, повторно рассмотрим пример из предыдущего урока. В примере используем регулярное выражение, чтобы найти RGB-значения в блоке HTML-кода:

Текст

<BODY BGCOLOR="#336633" TEXT="#FFFFFF" 
      MARGINWIDTH="0" MARGINHEIGHT="0"
      TOPMARGIN="0" LEFTMARGIN="0">

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

#[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]

Результат

<BODY BGCOLOR="#336633" TEXT="#FFFFFF" 
      MARGINWIDTH="0" MARGINHEIGHT="0"
      TOPMARGIN="0" LEFTMARGIN="0">

В шаблоне, использованном в предыдущем уроке, набор символов [0-9A-Fa-f] повторялся шесть раз. Здесь каждый набор [0-9A-Fa-f] был заменен на [[:xdigit:]]. Результат тот же самый.

Обратите внимание, что регулярное выражение, используемое в этом примере, начинается с [[ и заканчивается ]] (два набора скобок). Это важно и обязательно при использовании классов POSIX. Классы POSIX заключаются в «скобки» [: и :]; мы использовали выражение POSIX [:xdigit:] (а не :xdigit:). Внешние скобки [ и ] определяют набор; а внутренние скобки [ и ] сами являются частью имени класса POSIX.

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

Резюме

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

Регулярные выражения (их еще называют 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-канале

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