Шпаргалка по регулярным выражениям. В примерах
Регулярные выражения (regex или regexp) очень эффективны для извлечения информации из текста. Для этого нужно произвести поиск одного или нескольких совпадений по определённому шаблону (т. е. определённой последовательности символов ASCII или unicode).
Области применения regex разнообразны, от валидации до парсинга/замены строк, передачи данных в другие форматы и Web Scraping’а.
Одна из любопытных особенностей регулярных выражений в их универсальности, стоит вам выучить синтаксис, и вы сможете применять их в любом (почти) языке программирования (JavaScript, Java, VB, C #, C / C++, Python, Perl, Ruby, Delphi, R, Tcl, и многих других). Небольшие отличия касаются только наиболее продвинутых функций и версий синтаксиса, поддерживаемых движком.
Давайте начнём с нескольких примеров.
Основы
Якоря — ^ и $
Квантификаторы — * + ? и <>
Оператор ИЛИ — | или []
Символьные классы — \d \w \s и .
Используйте оператор . с осторожностью, так как зачастую класс или отрицаемый класс символов (который мы рассмотрим далее) быстрее и точнее.
У операторов \d , \w и \s также есть отрицания ― \D, \W и \S соответственно.
Например, оператор \D будет искать соответствия противоположенные \d .
Непечатаемые символы также можно искать, например табуляцию \t , новую строку \n , возврат каретки \r .
Флаги
Мы научились строить регулярные выражения, но забыли о фундаментальной концепции ― флагах.
Регулярное выражение, как правило, записывается в такой форме / abc /, где шаблон для сопоставления выделен двумя слешами / . В конце выражения, мы определяем значение флага (эти значения можно комбинировать):
- g (global) ― не возвращает результат после первого совпадения, а продолжает поиск с конца предыдущего совпадения.
- m (multi line) ― с таким флагом, операторы ^ и $ вызовут совпадение в начале и конце строки ввода (line), вместо строки целиком (string).
- i (insensitive) ― делает выражение регистронезависимым (например, /aBc/i соответствует AbC).
Средний уровень
Скобочные группы ― ()
Этот оператор очень полезен, когда нужно извлечь информацию из строк или данных, используя ваш любимый язык программирования. Любые множественные совпадения, по нескольким группам, будут представлены в виде классического массива: доступ к их значениям можно получить с помощью индекса из результатов сопоставления.
Если присвоить группам имена (используя (?<foo>. ) ), то можно получить их значения, используя результат сопоставления, как словарь, где ключами будут имена каждой группы.
Скобочные выражения ― []
Помните, что внутри скобочных выражений все специальные символы (включая обратную косую черту \ ) теряют своё служебное значение, поэтому нам ненужно их экранировать.
Жадные и ленивые сопоставления
Квантификаторы ( * + <> ) ― это «жадные» операторы, потому что они продолжают поиск соответствий, как можно глубже ― через весь текст.
Например, выражение <.+> соответствует <div>simple div</div> в This is a <div> simple div</div> test . Чтобы найти только тэг div ― можно использовать оператор ? , сделав выражение «ленивым»:
Обратите внимание, что хорошей практикой считается не использовать оператор . , в пользу более строгого выражения:
Продвинутый уровень
Границы слов ― \b и \B
\b ― соответствует границе слова, наподобие якоря (он похож на $ и ^ ), где предыдущий символ ― словесный (например, \w ), а следующий ― нет, либо наоборот, (например, это может быть начало строки или пробел).
\B ― соответствует несловообразующей границе. Соответствие не должно обнаруживаться на границе \b .
Обратные ссылки — \1
Опережающие и ретроспективные проверки — (?=) and (?<=)
Вы можете использовать оператор отрицания !
Заключение
Как вы могли убедиться, области применения регулярных выражений разнообразны. Я уверен, что вы сталкивались с похожими задачами в своей работе (хотя бы с одной из них), например такими:
Name already in use
backend-cheats / files / programming-language / regex-cheatsheet.md
- Go to file T
- Go to line L
- Copy path
- Copy permalink
- Open with Desktop
- View raw
- Copy raw contents Copy raw contents
Copy raw contents
Copy raw contents
Шпаргалка по регулярным выражениям
Содержание:
Регулярные выражения – это мощный инструмент для поиска и замены слов в тексте. Само регулярное выражение представляет из себя обычную строку составленную по определенным правилами. В общем виде она представляет из себя две косые черты / / , где после первой черты идёт специальный паттерн для поиска, а после второй – набор флагов.
Для тренировки использования регулярных выражений можно воспользоваться сайтом Regex101.com.
Также можно воспользоваться возможностями для работы с регулярными выражениями в одном из языков программирования. Вот примеры для Python, JavaScript, Go, Kotlin, C# и так далее
Возьмем для примера любой текст. Представим, что в этом тексте нам нужно найти все слова London . Это самый простой случай использования регулярных выражения, нам всего лишь необходимо вписать нужное слово между косыми чертами:
Флаги влияют на результат поиска. Их всего 5 штук:
- i – позволяет игнорировать регистры букв (нет разницы между A и a).
- g – позволяет искать все совпадения в тексте, без него – только первое.
- m – включение многострочного режима (влияет только на поведение ^ и $ ).
- s – текст трактуется как одна строка, в этом случае метасимволу . (точка) соответствует любой одиночный символ, включая символ новой строки.
- u – unicode-трактовка. Выражение может содержать специальные паттерны, характерные для юникода.
На месте точки может быть любой символ. Количеством точек можно определять длину слов.
take look team hike track time
Позволяют указать определенный перечень символов.
Позволяет исключить определенный набор символ из поиска, используется вместе с квадратными скобками.
Указывает диапазон с первого по последний символ (включительно) в алфавитном порядке.
Аналогично работает с цифрами:
Звездочка после символа указывает, что данный символ может отсутствовать, либо совпадать один или более раз.
Плюс после символа указывает, что данный символ должен присутствовать один или более раз.
Вопросительный знак после символа указывает, что данный символ является не обязательным (может либо отсутствовать, либо встрачаться только один раз).
Чтобы указать точное количеcтво повторений, необходимо после символа записать фигурные скобки с нужным числом.
Чтобы указать диапазон повторений, необходимо после символа записать фигурный скобки с нужным диапазоном, разделенным запятой.
Верхнюю границу можно опускать. Например, запись a <3,>говорит о том, что символ a должен встречаться не менее трёх раз.
Скобки позволяют сгруппировать любую последовательность символов, чтобы в дальнейшем обращается к ним используя выражение \число , где число — порядковый номер сгруппированной последовательности.
Чтобы игнорировать сохранение группы используется конструкция (?:) .
Группам можно задавать любые имена. Для этого используется конструкция — (?P<Name>. ) , где Name — название, . — любая последовательность символов. Для обращения к именованным группам используется конструкция — (?P=Name) .
Если у Вас возникли трудности с пониманием группировки, советую посмотреть данное видео.
Вертикальная черта позволяет указывать альтернативные варианты для поиска. Это чем-то похоже на использование квадратных скобок [abc] , но только вертикальная черта может работать с целыми словами и выражениями, а не только с отдельными символами.
Для того, чтобы использовать в поиске специальные символы <> [] / \ + *. $ ^ |? , необходимо поставить впереди знак косой черты \ .
What now What next Times up Wake up
Поиск в начале строки ^
Символ каретки в регулярном выражении говорит о том, что поиск производится только по началу строк.
Поиск в конце строки $
Символ доллара в регулярном выражении говорит о том, что поиск производится только по концу строк.
Для более удобного поиска целого класса символов существуют встроенные обозначения.
Наборы и диапазоны [. ]
Несколько символов или символьных классов в квадратных скобках […] означают «искать любой символ из заданных».
Наборы
Для примера, [eao] означает любой из 3-х символов: ‘a’ , ‘e’ или ‘o’ .
Это называется набором.
Наборы могут использоваться в регулярных выражениях вместе с обычными символами, например:
Обратите внимание, что в наборе несколько символов, но в результате он соответствует ровно одному символу.
Так что этот пример не даёт совпадений:
- В ,
- затем один из символов [уа] ,
- потом ля .
В этом случае совпадениями могут быть Вуля или Валя .
Диапазоны
Ещё квадратные скобки могут содержать диапазоны символов.
К примеру, [a-z] соответствует символу в диапазоне от a до z , или [0-5] – цифра от 0 до 5 .
В приведённом ниже примере мы ищем "x" , за которым следуют две цифры или буквы от A до F :
Здесь в [0-9A-F] сразу два диапазона: ищется символ, который либо цифра от 0 до 9 , либо буква от A до F .
Если мы хотим найти буквы и в верхнем и в нижнем регистре, то мы можем добавить ещё диапазон a-f : [0-9A-Fa-f] . Или поставить у регулярного выражения флаг i .
Также мы можем использовать символьные классы внутри […] .
Например, если мы хотим найти «символ слова» \w или дефис — , то набор будет: [\w-] .
Можем использовать и несколько классов вместе, например [\s\d] означает «пробельный символ или цифра».
Символьные классы – не более чем сокращение для наборов символов.
- \d – то же самое, что и [0-9] ,
- \w – то же самое, что и [a-zA-Z0-9_] ,
- \s – то же самое, что и [\t\n\v\f\r ] , плюс несколько редких пробельных символов Юникода.
Пример: многоязычный аналог \w
Так как символьный класс \w является всего лишь сокращением для [a-zA-Z0-9_] , он не найдёт китайские иероглифы, кириллические буквы и т.п.
Давайте сделаем более универсальный шаблон, который ищет символы, используемые в словах, для любого языка. Это очень легко с Юникод-свойствами: [\p
Расшифруем его. По аналогии с классом \w , мы делаем свой набор, который включает в себя символы со следующими Юникодными свойствами:
- Alphabetic ( Alpha ) – для букв,
- Mark ( M ) – для акцентов,
- Decimal_Number ( Nd ) – для цифр,
- Connector_Punctuation ( Pc ) – для символа подчёркивания ‘_’ и подобных ему,
- Join_Control ( Join_C ) – два специальных кода 200c и 200d , используемые в лигатурах, например, арабских.
Конечно, этот шаблон можно адаптировать: добавить Юникодные свойства или убрать. Более подробно о них было рассказано в главе Юникод: флаг "u" и класс \p .
Поддержка Юникодных свойств p <…>была добавлена в Edge и Firefox относительно недавно. Если нужно реализовать поддержку p <…>для устаревших версий этих браузеров, можно использовать библиотеку XRegExp.
Или же использовать диапазоны символов в интересующем нас языке, например [а-я] для кириллицы.
Исключающие диапазоны
Помимо обычных диапазонов, есть «исключающие» диапазоны, которые выглядят как [^…] .
Они обозначаются символом каретки ^ в начале диапазона и соответствуют любому символу за исключением заданных.
- [^aeyo] – любой символ, за исключением ‘a’ , ‘e’ , ‘y’ или ‘o’ .
- [^0-9] – любой символ, за исключением цифры, то же, что и \D .
- [^\s] – любой непробельный символ, то же, что и \S .
Пример ниже ищет любые символы, кроме латинских букв, цифр и пробелов:
Экранирование внутри […]
Обычно, когда мы хотим найти специальный символ, нам нужно экранировать его, например \. . А если нам нужна обратная косая черта, тогда используем \\ , т.п.
В квадратных скобках большинство специальных символов можно использовать без экранирования:
- Символы . + ( ) не нужно экранировать никогда.
- Тире — не надо экранировать в начале или в конце (где оно не задаёт диапазон).
- Символ каретки ^ нужно экранировать только в начале (где он означает исключение).
- Закрывающую квадратную скобку ] , если нужен именно такой символ, экранировать нужно.
Другими словами, разрешены без экранирования все специальные символы, кроме случаев, когда они означают что-то особое в наборах.
Точка . внутри квадратных скобок – просто точка. Шаблон [.,] будет искать один из символов: точку или запятую.
В приведённом ниже примере регулярное выражение [-().^+] ищет один из символов -().^+ :
…Впрочем, если вы решите экранировать «на всякий случай», то не будет никакого вреда:
Наборы и флаг «u»
Если в наборе есть суррогатные пары, для корректной работы обязательно нужен флаг u .
Например, давайте попробуем найти шаблон [] в строке :
Результат неверный, потому что по умолчанию регулярные выражения «не знают» о существовании суррогатных пар.
Движок регулярных выражений думает, что [] – это не два, а четыре символа:
- левая половина от (1) ,
- правая половина от (2) ,
- левая половина от (3) ,
- правая половина от (4) .
Мы даже можем вывести их коды:
То есть в нашем примере выше ищется и выводится только левая половина от .
Если добавить флаг u , то всё будет в порядке:
Аналогичная ситуация произойдёт при попытке искать диапазон: [-] .
Если мы забудем флаг u , то можем нечаянно получить ошибку:
Причина в том, что без флага u суррогатные пары воспринимаются как два символа, так что [-] воспринимается как [<55349><56499>-<55349><56500>] (каждая суррогатная пара заменена на коды). Теперь уже отлично видно, что диапазон 56499-55349 некорректен: его левая граница больше правой, это и есть формальная причина ошибки.
Регулярные выражения: начало работы с RegExp
Давайте разберёмся, что же собой представляют регулярные выражения. Если вам когда-нибудь приходилось работать с командной строкой, вы, вероятно, использовали маски имён файлов. Например, чтобы удалить все файлы в текущей директории, которые начинаются с буквы «d», можно написать rm d* .
Регулярные выражения представляют собой похожий, но гораздо более сильный инструмент для поиска строк, проверки их на соответствие какому-либо шаблону и другой подобной работы. Англоязычное название этого инструмента — Regular Expressions или просто RegExp. Строго говоря, регулярные выражения — специальный язык для описания шаблонов строк.
Реализация этого инструмента различается в разных языках программирования, хоть и не сильно. В данной статье мы будем ориентироваться в первую очередь на реализацию Perl Compatible Regular Expressions.
Основы синтаксиса
В первую очередь стоит заметить, что любая строка сама по себе является регулярным выражением. Так, выражению Хаха , очевидно, будет соответствовать строка «Хаха» и только она. Регулярки являются регистрозависимыми, поэтому строка «хаха» (с маленькой буквы) уже не будет соответствовать выражению выше.
Однако уже здесь следует быть аккуратным — как и любой язык, регекспы имеют спецсимволы, которые нужно экранировать. Вот их список: . ^ $ * + ? < >[ ] \ | ( ) . Экранирование осуществляется обычным способом — добавлением \ перед спецсимволом.
Набор символов
Предположим, мы хотим найти в тексте все междометия, обозначающие смех. Просто Хаха нам не подойдёт — ведь под него не попадут «Хехе», «Хохо» и «Хихи». Да и проблему с регистром первой буквы нужно как-то решить.
Здесь нам на помощь придут наборы — вместо указания конкретного символа, мы можем записать целый список, и если в исследуемой строке на указанном месте будет стоять любой из перечисленных символов, строка будет считаться подходящей. Наборы записываются в квадратных скобках — паттерну [abcd] будет соответствовать любой из символов «a», «b», «c» или «d».
Внутри набора большая часть спецсимволов не нуждается в экранировании, однако использование \ перед ними не будет считаться ошибкой. По прежнему необходимо экранировать символы «\» и «^», и, желательно, «]» (так, [][] обозначает любой из символов «]» или «[», тогда как [[]х] — исключительно последовательность «[х]»). Необычное на первый взгляд поведение регулярок с символом «]» на самом деле определяется известными правилами, но гораздо легче просто экранировать этот символ, чем их запоминать. Кроме этого, экранировать нужно символ «-», он используется для задания диапазонов (см. ниже).
Если сразу после [ записать символ ^ , то набор приобретёт обратный смысл — подходящим будет считаться любой символ кроме указанных. Так, паттерну [^xyz] соответствует любой символ, кроме, собственно, «x», «y» или «z».
Итак, применяя данный инструмент к нашему случаю, если мы напишем [Хх][аоие]х[аоие] , то каждая из строк «Хаха», «хехе», «хихи» и даже «Хохо» будут соответствовать шаблону.
Предопределённые классы символов
Для некоторых наборов, которые используются достаточно часто, существуют специальные шаблоны. Так, для описания любого пробельного символа (пробел, табуляция, перенос строки) используется \s , для цифр — \d , для символов латиницы, цифр и подчёркивания «_» — \w .
Если необходимо описать вообще любой символ, для этого используется точка — . . Если указанные классы написать с заглавной буквы ( \S , \D , \W ) то они поменяют свой смысл на противоположный — любой непробельный символ, любой символ, который не является цифрой, и любой символ кроме латиницы, цифр или подчёркивания соответственно.
Также с помощью регулярных выражений есть возможность проверить положение строки относительно остального текста. Выражение \b обозначает границу слова, \B — не границу слова, ^ — начало текста, а $ — конец. Так, по паттерну \bJava\b в строке «Java and JavaScript» найдутся первые 4 символа, а по паттерну \bJava\B — символы c 10-го по 13-й (в составе слова «JavaScript»).
Комикс про регулярные выражения с xkcd.ru
Диапазоны
У вас может возникнуть необходимость обозначить набор, в который входят буквы, например, от «б» до «ф». Вместо того, чтобы писать [бвгдежзиклмнопрстуф] можно воспользоваться механизмом диапазонов и написать [б-ф] . Так, паттерну x[0-8A-F][0-8A-F] соответствует строка «xA6», но не соответствует «xb9» (во-первых, из-за того, что в диапазоне указаны только заглавные буквы, во-вторых, из-за того, что 9 не входит в промежуток 0-8).
Механизм диапазонов особенно актуален для русского языка, ведь для него нет конструкции, аналогичной \w . Чтобы обозначить все буквы русского алфавита, можно использовать паттерн [а-яА-ЯёЁ] . Обратите внимание, что буква «ё» не включается в общий диапазон букв, и её нужно указывать отдельно.
Квантификаторы
Вернёмся к нашему примеру. Что, если в «смеющемся» междометии будет больше одной гласной между буквами «х», например «Хаахаааа»? Наша старая регулярка уже не сможет нам помочь. Здесь нам придётся воспользоваться квантификаторами.
Примеры использования квантификаторов в регулярных выражениях
Обратите внимание, что квантификатор применяется только к символу, который стоит перед ним.
Некоторые часто используемые конструкции получили в языке RegEx специальные обозначения:
Спецобозначения квантификаторов в регулярных выражениях.
Таким образом, с помощью квантификаторов мы можем улучшить наш шаблон для междометий до [Хх][аоеи]+х[аоеи]* , и он сможет распознавать строки «Хааха», «хееееех» и «Хихии».
Ленивая квантификация
Предположим, перед нами стоит задача — найти все HTML-теги в строке
Очевидное решение <.*> здесь не сработает — оно найдёт всю строку целиком, т.к. она начинается с тега абзаца и им же заканчивается. То есть содержимым тега будет считаться строка
Это происходит из-за того, что по умолчанию квантификатор работают по т.н. жадному алгоритму — старается вернуть как можно более длинную строку, соответствующую условию. Решить проблему можно двумя способами. Первый — использовать выражение <[^>]*> , которое запретит считать содержимым тега правую угловую скобку. Второй — объявить квантификатор не жадным, а ленивым. Делается это с помощью добавления справа к квантификатору символа ? . Т.е. для поиска всех тегов выражение обратится в <.*?> .
Ревнивая квантификация
Иногда для увеличения скорости поиска (особенно в тех случаях, когда строка не соответствует регулярному выражению) можно использовать запрет алгоритму возвращаться к предыдущим шагам поиска для того, чтобы найти возможные соответствия для оставшейся части RegExp. Это называется ревнивой квантификацией. Квантификатор делается ревнивым с помощью добавления к нему справа символа + . Ещё одно применение ревнивой квантификации — исключение нежелательных совпадений. Так, паттерну ab*+a в строке «ababa» будут соответствовать только первые три символа, но не символы с третьего по пятый, т.к. символ «a», который стоит на третьей позиции, уже был использован для первого результата.
Чуть больше о жадном, сверхжадном и ленивом режимах квантификации вы сможете узнать из статьи о регулярных выражениях в Java.
Скобочные группы
Для нашего шаблона «смеющегося» междометия осталась самая малость — учесть, что буква «х» может встречаться более одного раза, например, «Хахахахааахахооо», а может и вовсе заканчиваться на букве «х». Вероятно, здесь нужно применить квантификатор для группы [аиое]+х , но если мы просто напишем [аиое]х+ , то квантификатор + будет относиться только к символу «х», а не ко всему выражению. Чтобы это исправить, выражение нужно взять в круглые скобки: ([аиое]х)+ .
Таким образом, наше выражение превращается в [Хх]([аиое]х?)+ — сначала идёт заглавная или строчная «х», а потом произвольное ненулевое количество гласных, которые (возможно, но не обязательно) перемежаются одиночными строчными «х». Однако это выражение решает проблему лишь частично — под это выражение попадут и такие строки, как, например, «хихахех» — кто-то может быть так и смеётся, но допущение весьма сомнительное. Очевидно, мы можем использовать набор из всех гласных лишь единожды, а потом должны как-то опираться на результат первого поиска. Но как?…
Запоминание результата поиска по группе
Оказывается, результат поиска по скобочной группе записывается в отдельную ячейку памяти, доступ к которой доступен для использования в последующих частях регэкспа. Возвращаясь к задаче с поиском HTML-тегов на странице, нам может понадобиться не только найти теги, но и узнать их название. В этом нам может помочь регулярное выражение <(.*?)> .
На результат поиска по группе можно ссылаться с помощью выражения \n , где n — цифра от 1 до 9. Например выражению (\w)(\w)\1\2 соответствуют строки «aaaa», «abab», но не соответствует «aabb».
Если выражение берётся в скобки только для применения к ней квантификатора (не планируется запоминать результат поиска по этой группе), то сразу после первой скобки стоит добавить ?: , например (?:[abcd]+\w) .
С использованием этого механизма мы можем переписать наше выражение к виду [Хх]([аоие])х?(?:\1х?)* .
Перечисление
Чтобы проверить, удовлетворяет ли строка хотя бы одному из шаблонов, можно воспользоваться аналогом булевого оператора OR, который записывается с помощью символа | . Так, под шаблон Анна|Одиночество попадают строки «Анна» и «Одиночество» соответственно. Особенно удобно использовать перечисления внутри скобочных групп. Так, например (?:a|b|c|d) полностью эквивалентно [abcd] (в данном случае второй вариант предпочтительнее в силу производительности и читаемости).
С помощью этого оператора мы сможем добавить к нашему регулярному выражению для поиска междометий возможность распознавать смех вида «Ахахаах» — единственной усмешке, которая начинается с гласной: [Хх]([аоие])х?(?:\1х?)*|[Аа]х?(?:ах?)+
Полезные сервисы
Потренироваться и/или проверить регулярное выражение на каком-либо тексте без написания кода можно с помощью таких сервисов, как RegExr, Regexpal или Regex101. Последний, вдобавок, приводит краткие пояснения к тому, как регулярка работает.
Разобраться, как работает регулярное выражение, которое попало к вам в руки, можно с помощью сервиса Regexper — он умеет строить понятные диаграмы по регуляркам.
RegExp Builder — визуальный конструктор функций JavaScript для работы с регулярными выражениями.
Больше инструментов можно найти в нашей подборке.
Задания для закрепления
Найдите время
Время имеет формат часы:минуты. И часы, и минуты состоят из двух цифр, пример: 09:00. Напишите RegEx выражение для поиска времени в строке: «Завтрак в 09:00». Учтите, что «37:98» — некорректное время.
Java[^script]
Найдет ли регулярка Java[^script] что-нибудь в строке Java? А в строке JavaScript?
- В строке Java он ничего не найдёт, так как исключающие квадратные скобки в Java[^…] означают «один символ, кроме указанных». А после «Java» – конец строки, символов больше нет.
- Да, найдёт. Поскольку регэксп регистрозависим, то под [^script] вполне подходит символ «S».
Напишите регулярное выражение для поиска HTML-цвета, заданного как #ABCDEF, то есть # и содержит затем 6 шестнадцатеричных символов.
Итак, нужно написать выражение для описания цвета, который начинается с «#», за которым следуют 6 шестнадцатеричных символов. Шестнадцатеричный символ можно описать с помощью [0-9a-fA-F] . Для его шестикратного повторения мы будем использовать квантификатор <6>.
Разобрать арифметическое выражение
Арифметическое выражение состоит из двух чисел и операции между ними, например:
- 1 + 2
- 1.2 *3.4
- -3/ -6
- -2-2
Также могут присутствовать пробелы вокруг оператора и чисел.
Напишите регулярку, которая найдёт, как всё арифметическое действие, так и (через группы) два операнда.
Регулярное выражение для числа, возможно, дробного и отрицательного: -?\d+(\.\d+)? .
Оператор – это [+*/\-] . Заметим, что дефис мы экранируем. Нам нужно число, затем оператор, затем число, и необязательные пробелы между ними. Чтобы получить результат в требуемом формате, добавим ?: к группам, поиск по которым нам не интересен (отдельно дробные части), а операнды наоборот заключим в скобки. В итоге:
Кроссворды из регулярных выражений
Такие кроссворды вы можете найти у нас.
Удачи и помните — не всегда задачу стоит решать именно с помощью регекспов («У программиста была проблема, которую он начал решать регэкспами. Теперь у него две проблемы»). Иногда лучше, например, написать развёрнутый автомат конечных состояний.