December 8, 2019

Регулярные выражения для начинающих

Регулярные выражения – выражения, состоящие из части текста и формул, позволяющие находить определенный кусок текста в строке. Они используются в тех случаях, когда мы вытаскиваем XPATHом текст, а из текста нам нужно вытащить определенное слово или набор каких-либо символов. Или нам приходит ответ от запроса в json и нам так же нужно вытащить что-то из вышеперечисленного.

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

\d – отвечает за любую цифру (0-9)

\D – отвечает за пробел и любой символ, кроме цифры (a-zA-Z@#$% и тд)

\w – отвечает за любую букву или цифру и за знак подчеркивания (0-9a-zA-Z и _ )

\W – отвечает за пробел и любой символ, кроме цифр, букв и знака подчеркивания («№;@#$%^ и тд)

\s – отвечает за пробел

\S – отвечает за любой символ, кроме пробела (0-9a-zA-Z!@#$%$^& и тд)

Примечание: буквы русского языка (как и любого другого, в котором нет английских букв) будут считаться символами, а не буквами!

Всего 6 параметров. Каждый из них в отдельности отвечает за 1 определенный символ или пробел.

Еще есть знак “+”. Если его поставить после любого из этих 6 параметров, это будет означать от одного символа до любого числа символов или пробелов. Скажу сразу, что у всего есть границы и о них будет расписано ниже.

Давайте на примере обычного предложения рассмотрим эти параметры.

Предложение: He said me:”I was born in 1980!”

РВ на само предложение можно написать по-разному. Покажу пару примеров с объяснением:

\w\w\s\w\w\w\w\s\w\w\W\W\w\s\w\w\w\s\w\w\w\w\s\w\w\s\d\d\d\d\W\W

\w\w – отвечают за слово He, т.к. \w – любая буква

\s – отвечает за пробел после слова He, т.к. \s – пробел

\w\w\w\w – отвечают за слово said

\s – снова пробел

\w\w – отвечают за слово me

\W\W – первая \W отвечает за знак двоеточия (:), и вторая \W отвечает за знак открывающейся кавычки (), т.к. \W – любой символ, кроме цифр, букв и знака подчеркивания

\w – отвечает за слово I

\s – снова пробел

\w\w\w – отвечают за слово born

\s – снова пробел

\w\w - отвечает за слово in

\s – снова пробел

\d\d\d\d – отвечают за число 1980, т.к. \d – любая цифра

\W\W – первая \W отвечает за восклицательный знак (!), и вторая \W отвечает за знак закрывающейся кавычки ()

Можете еще раз посмотреть и сравнить это предложения и формулу

He said me:”I was born in 1980!”

\w\w\s\w\w\w\w\s\w\w\W\W\w\s\w\w\w\s\w\w\w\w\s\w\w\s\d\d\d\d\W\W

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

Еще один вариант написания:

\w+\s\S+\s\w+\S+\s\w+\s\D+\w+\S+

Выглядит короче, но не понятнее, давайте подробно разберем:

\w+ - помним, что \w это любая буква или цифра, или знак подчеркивания, то \w+ это любое количество букв, цифр и знаков подчеркивания (или все в вперемешку, например, duwe_rb2379g_fh2jfsbdofkjsbdf и тд).

Вы скажете, что написал \w+ и вот тебе все предложение. Не все так просто, т.к. \w не отвечает за пробел (а еще за любые другие символы типа !$#@ и тд), а у нас в предложении после слова He идет пробел. А значит, \w+ будет обозначать только слово He, т.к. действует до первого пробела

\s – отвечает за пробел после слова He

\S+ - тоже самое, что и с \w+. Т.к. \S это вообще любой символ, кроме пробела, то и \S+ будет считать все символы до первого попавшегося ей пробела. В нашем случае это всего лишь слово said

\s – отвечает за пробел после слова said

\w+ - опять же, любое количество букв, цифр и знаков подчеркивания, ДО первого пробела или знака, за который не отвечает \w. У нас это слово me

\S+ - вот здесь момент интереснее. После слова me у нас нет пробела, а сразу идет двоеточие, открывающаяся кавычка и слово I. Т.к. \S это вообще любой символ, то \S+ может отвечать за все эти три составляющие. В нашем случае это :”I

На самом деле здесь есть спорный момент. В любом случае \w+\S+ будет отвечать за кусок текста me:”I, потому что перед ним и после него стоят пробелы. Здесь \w+ может отвечать, как и за me, так и за m. Это получается за счет того, что после \w+ у нас стоит \S+, которое может отвечать и за букву e тоже.

Поэтому, чтобы не было путаницы в дальнейшем, такие моменты описывайте более точно, чтобы не было двусмыслицы. Т.е. если вам нужен вариант слева, то лучше описать его так - \w\w\S+ (здесь каждая \w отвечает за конкретную букву) или так \w+\W\S+(здесь разделителем выступает \W, отвечающее за двоеточие,). А в варианте как изображено справа, лучше написать просто \w\S+, где \w будет отвечать только за одну букву (т.к. без плюсика).

Идем дальше.

\s – пробел после I

\w+ - отвечает за слово was (все по той же аналогии)

\s – пробел после слова was

\D – еще один интересный момент. Этот параметр отвечает за все, кроме цифр. Поэтому в нашем предложении он обозначает такой кусок: born in . И слово born, и пробел после него, и слово in, и пробел после него. На самом деле, нашу регулярку можно было бы сократить и до такого вида: \D+\S+, где \D+ отвечал бы за все до числа 1980, а \S+ отвечал бы за 1980!”. Но пример составлен специально разнообразнее, чтоб рассмотреть больше разных случаев.

\w+ - отвечает за число (цифры) 1980

\S+ - отвечает за восклицательный знак (!) и знак закрывающейся кавычки ()

Тут такой же спорный момент с куском 1980!”, понять, за сколько конкретно цифр отвечает \w+ нет возможности (за одну, за две, за три или за все четыре). Поэтому лучше также прописать более точную формулу для этого куска. Но все в зависимости от того, что я принял за \w+. В примере приняли за все число 1980. А значит формула будет выглядеть так \w\w\w\w\S+ или так \d\d\d\d\S+, а лучше даже так \d+\W+.

Мы разобрали два примера, которые дают понять суть применения параметров. Но сама регулярка пишется для того, чтобы достать что-то из текста. Для этого нам потребуется еще один параметр

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

Давайте сразу разберем, как это работает. Например, из того же предложения нам нужно достать число 1980.

Предложение: He said me:”I was born in 1980!”

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

\w+\s\S+\s\w+\S+\s\w+\s\D+\d+\W+

За число 1980 здесь отвечает \d+. И теперь, чтобы регулярка нам выводила только число 1980, мы возьмем \d+ в круглые скобки. Получим:

\w+\s\S+\s\w+\S+\s\w+\s\D+(\d+)\W+

Такие сложные регулярки обычно пишутся, если нам нужно что-то вытащить из html текста. Чаще всего мы работаем регулярками либо с обычным текстом, либо c ответом запроса в виде json, который считается также обычным текстом. Поэтому на деле все еще проще, т.к. нам понадобится лишь прописать формулу для искомого куска текста (в примере выше это было (\d+)), и определить правильные границы нашей формулы.

А самое главное, в тексте эти границы можно писать тем же текстом. Что это значит? Давайте посмотрим, как еще можно было вытащить число 1980 из примера выше.

in (\d+)!

Вот так просто. В двух словах: просто записали число точной формулой (\d+ это только цифры), выделили круглыми скобками (чтоб результатом регулярки было только число) и с обеих сторон написали границы (т.е. просто дописали текст, который был в примере до числа 1980 и после него). Кстати, не нужно писать все начало предложения целиком, потому что в самом предложении слово in фигурирует только один раз, как и то, что после него идет пробел, какое-то число и восклицательный знак. Т.е. в самом регулярном выражении мы как бы прописываем то, что будет точно определять какой-либо кусок текста.

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

Само собой все дается с опытом, но и бывает, попадаются очень длинные строки с похожими как бы сказать символьными конструкциями, что регулярку с ходу таки не напишешь. Для этого я пользуюсь (и вам советую тоже) конструктором регулярных выражений: https://bablosoft.github.io/RegexpConstructor/#!/regexptest

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

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

Нам пришло с запроса что-то подобное (пример из головы):

{[info]; <username: “John12”; userID: “134284”; geo: “GE”; old: “35”; status: “online”>; <username: “Sam_Sam”; userID: “132050”; geo: “AU”; old: “42”; status: “online”>; <username: “22Andy22”; userID: “786512”; geo: “UK”; old: “31”; status: “offline”>; <username: “AndreAn”; userID: “879652”; geo: “FR”; old: “67”; status: “offline”>; <username: “@SPAMTRAF”; userID: “379863”; geo: “SE”; old: “24”; status: “online”>}

Мы видим, что здесь есть и ники (имена), и id, и гео и тд. Допустим, для нашей работы нам требуются id пользователей. Как будет выглядеть регулярка. Очень просто. id состоит из цифр (в нашем случае их 6), то здесь можно написать либо \d\d\d\d\d\d, либо \d+. Первый вариант более конкретный, который всегда будет отвечать за 6 цифр. Поэтому, если вы уверены, что id всех пользователей всегда равен 6 цифрам, то все в порядке. Если нет, лучше возьмите более универсальную \d+. Мы возьмем второй вариант: \d+

Выделяем \d+ в круглые скобки: (\d+)

Далее, пишем границу слева, в нашем случае написать просто кавычки недостаточно, т.к. такая же формула подойдет и к значению old (там тоже идут цифры, но если бы мы взяли формулу \d\d\d\d\d\d, то обошлись бы просто формулой (\d\d\d\d\d\d) , т.к. нигде больше 6 цифр не пишется). Поэтому распишем побольше: ID: \W(\d+)

Здесь, как вы видите, заменили кавычки на \W, т.к. не все символы из текста читаются как текст, поэтому будьте внимательны и при работе с ними, заменяйте их на параметры, отвечающие за знаки (\S;\W;\D). Хотя двоеточие нормально зашло, так что проверяйте, не напутали вы что-либо со знаками.

И пишем границу справа, здесь уже сойдут обычные кавычки (ставлю \W): ID: \W(\d+)\W

Вот мы и получили регулярку для вытаскивания id пользователей.

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

С такими никами ставим (\S+) – это будет отвечать за вытаскивание ников, какими бы они разнообразными не были (пробелов в никах как правило не бывает).

Здесь основная работа идет с определением границ. Видно, что слово username используется только перед никами, вот его то мы и возьмем за левую границу. Получаем: username: \W(\S+)

За правую границу взять только кавычки будет тоже недостаточно, т.к. наша \S+ может их захватить с собой и на параметр \W оставить знак точки с запятой (;). Поэтому мы добавим и \W, и знак точки запятой, чтоб РВ поняла, что \W отвечает за кавычки.

В итоге получаем РВ: username: \W(\S+)\W; которая будет выдавать нам username, какой бы длины они не были и какие бы они символы не содержали.

Подписывайтесь на канал https://t.me/SPAMTRAF