Анализ текста регулярными выражениями (RegExp) в Excel
Одной из самых трудоемких и неприятных задач при работе с текстом в Excel является парсинг - разбор буквенно-цифровой "каши" на составляющие и извлечение из нее нужных нам фрагментов. Например:
- извлечение почтового индекса из адреса (хорошо, если индекс всегда в начале, а если нет?)
- нахождение номера и даты счета из описания платежа в банковской выписке
- извлечение ИНН из разношерстных описаний компаний в списке контрагентов
- поиск номера автомобиля или артикула товара в описании и т.д.
Обычно во подобных случаях, после получасового муторного ковыряния в тексте вручную, в голову начинают приходить мысли как-то автоматизировать этот процесс (особенно если данных много). Решений тут несколько и с разной степенью сложности-эффективности:
- Использовать встроенные текстовые функции Excel для поиска-нарезки-склейки текста: ЛЕВСИМВ (LEFT), ПРАВСИМВ (RIGHT), ПСТР (MID), СЦЕПИТЬ (CONCATENATE) и ее аналоги, ОБЪЕДИНИТЬ (JOINTEXT), СОВПАД (EXACT) и т.д. Этот способ хорош, если в тексте есть четкая логика (например, индекс всегда в начале адреса). В противном случае формулы существенно усложняются и, порой, дело доходит даже до формул массива, что сильно тормозит на больших таблицах.
- Использование оператора проверки текстового подобия Like из Visual Basic, обернутого в пользовательскую макро-функцию. Это позволяет реализовать более гибкий поиск с использованием символов подстановки (*,#,? и т.д.) К сожалению, этот инструмент не умеет извлекать нужную подстроку из текста - только проверять, содержится ли она в нем.
Кроме вышеперечисленного, есть еще один подход, очень известный в узких кругах профессиональных программистов, веб-разработчиков и прочих технарей - это регулярные выражения (Regular Expressions = RegExp = "регэкспы" = "регулярки"). Упрощенно говоря, RegExp - это язык, где с помощью специальных символов и правил производится поиск нужных подстрок в тексте, их извлечение или замена на другой текст. Регулярные выражения - это очень мощный и красивый инструмент, на порядок превосходящий по возможностям все остальные способы работы с текстом. Многие языки программирования (C#, PHP, Perl, JavaScript...) и текстовые редакторы (Word, Notepad++...) поддерживают регулярные выражения.
Microsoft Excel, к сожалению, не имеет поддержки RegExp по-умолчанию "из коробки", но это легко исправить с помощью VBA. Откройте редактор Visual Basic с вкладки Разработчик (Developer) или сочетанием клавиш Alt+F11. Затем вставьте новый модуль через меню Insert - Module и скопируйте туда текст вот такой макрофункции:
Public Function RegExpExtract(Text As String, Pattern As String, Optional Item As Integer = 1) As String On Error GoTo ErrHandl Set regex = CreateObject("VBScript.RegExp") regex.Pattern = Pattern regex.Global = True If regex.Test(Text) Then Set matches = regex.Execute(Text) RegExpExtract = matches.Item(Item - 1) Exit Function End If ErrHandl: RegExpExtract = CVErr(xlErrValue) End Function
Теперь можно закрыть редактор Visual Basic и, вернувшись в Excel, опробовать нашу новую функцию. Синтаксис у нее следующий:
=RegExpExtract( Txt ; Pattern ; Item )
где
- Txt - ячейка с текстом, который мы проверяем и из которого хотим извлечь нужную нам подстроку
- Pattern - маска (шаблон) для поиска подстроки
- Item - порядковый номер подстроки, которую надо извлечь, если их несколько (если не указан, то выводится первое вхождение)
Самое интересное тут, конечно, это Pattern - строка-шаблон из спецсимволов "на языке" RegExp, которая и задает, что именно и где мы хотим найти. Вот самые основные из них - для начала:
Паттерн | Описание |
. |
Самое простое - это точка. Она обозначает любой символ в шаблоне на указанной позиции. |
\s |
Любой символ, выглядящий как пробел (пробел, табуляция или перенос строки). |
\S |
Анти-вариант предыдущего шаблона, т.е. любой НЕпробельный символ. |
\d |
Любая цифра |
\D |
Анти-вариант предыдущего, т.е. любая НЕ цифра |
\w |
Любой символ латиницы (A-Z), цифра или знак подчеркивания |
\W |
Анти-вариант предыдущего, т.е. не латиница, не цифра и не подчеркивание. |
[символы] |
В квадратных скобках можно указать один или несколько символов, разрешенных на указанной позиции в тексте. Например ст[уо]л будет соответствовать любому из слов: стол или стул. Также можно не перечислять символы, а задать их диапазоном через дефис, т.е. вместо [ABDCDEF] написать [A-F]. или вместо [4567] ввести [4-7]. Например, для обозначения всех символов кириллицы можно использовать шаблон [а-яА-ЯёЁ]. |
[^символы] |
Если после открывающей квадратной скобки добавить символ "крышки" ^, то набор приобретет обратный смысл - на указанной позиции в тексте будут разрешены все символы, кроме перечисленных. Так, шаблон [^ЖМ]уть найдет Путь или Суть или Забудь, но не Жуть или Муть, например. |
| |
Логический оператор ИЛИ (OR) для проверки по любому из указанных критериев. Например (счет|счёт|invoice) будет искать в тексте любое из указанных слов. Обычно набор вариантов заключается в скобки. |
^ |
Начало строки |
$ |
Конец строки |
\b |
Край слова |
Если мы ищем определенное количество символов, например, шестизначный почтовый индекс или все трехбуквенные коды товаров, то на помощь нам приходят квантификаторы или кванторы - специальные выражения, задающие количество искомых знаков. Квантификаторы применяются к тому символу, что стоит перед ним:
Квантор | Описание |
? |
Ноль или одно вхождение. Например .? будет означать один любой символ или его отсутствие. |
+ |
Одно или более вхождений. Например \d+ означает любое количество цифр (т.е. любое число от 0 до бесконечности). |
* |
Ноль или более вхождений, т.е. любое количество. Так \s* означает любое количество пробелов или их отсутствие. |
{число} или {число1,число2} |
Если нужно задать строго определенное количество вхождений, то оно задается в фигурных скобках. Например \d{6} означает строго шесть цифр, а шаблон \s{2,5} - от двух до пяти пробелов |
Теперь давайте перейдем к самому интересному - разбору применения созданной функции и того, что узнали о паттернах на практических примерах из жизни.
Извлекаем числа из текста
Для начала разберем простой случай - нужно извлечь из буквенно-цифровой каши первое число, например мощность источников бесперебойного питания из прайс-листа:
Логика работы регулярного выражения тут простая: \d - означает любую цифру, а квантор + говорит о том, что их количество должно быть одна или больше. Двойной минус перед функцией нужен, чтобы "на лету" преобразовать извлеченные символы в полноценное число из числа-как-текст.
Почтовый индекс
На первый взгляд, тут все просто - ищем ровно шесть цифр подряд. Используем спецсимвол \d для цифры и квантор {6} для количества знаков:
Однако, возможна ситуация, когда левее индекса в строке стоит еще один большой набор цифр подряд (номер телефона, ИНН, банковский счет и т.д.) Тогда наша регулярка выдернет из нее первых 6 цифр, т.е. сработает некорректно:
Чтобы этого не происходило, необходимо добавить в наше регулярное выражение по краям модификатор \b означающий конец слова. Это даст понять Excel, что нужный нам фрагмент (индекс) должен быть отдельным словом, а не частью другого фрагмента (номера телефона):
Телефон
Проблема с нахождением телефонного номера среди текста состоит в том, что существует очень много вариантов записи номеров - с дефисами и без, через пробелы, с кодом региона в скобках или без и т.д. Поэтому, на мой взгляд, проще сначала вычистить из исходного текста все эти символы с помощью нескольких вложенных друг в друга функций ПОДСТАВИТЬ (SUBSTITUTE), чтобы он склеился в единое целое, а потом уже примитивной регуляркой \d{11} вытаскивать 11 цифр подряд:
ИНН
Тут чуть сложнее, т.к. ИНН (в России) бывает 10-значный (у юрлиц) или 12-значный (у физлиц). Если не придираться особо, то вполне можно удовлетвориться регуляркой \d{10,12}, но она, строго говоря, будет вытаскивать все числа от 10 до 12 знаков, т.е. и ошибочно введенные 11-значные. Правильнее будет использовать два шаблона, связанных логическим ИЛИ оператором | (вертикальная черта):
Обратите внимание, что в запросе мы сначала ищем 12-разрядные, и только потом 10-разрядные числа. Если же записать нашу регулярку наоборот, то она будет вытаскивать для всех, даже длинных 12-разрядных ИНН, только первые 10 символов. То есть после срабатывания первого условия дальнейшая проверка уже не производится:
Это принципиальное отличие оператора | от стандартной экселевской логической функции ИЛИ (OR), где от перестановки аргументов результат не меняется.
Артикулы товаров
Во многих компаниях товарам и услугам присваиваются уникальные идентификаторы - артикулы, SAP-коды, SKU и т.д. Если в их обозначениях есть логика, то их можно легко вытаскивать из любого текста с помощью регулярных выражений. Например, если мы знаем, что наши артикулы всегда состоят из трех заглавных английских букв, дефиса и последующего трехразрядного числа, то:
Логика работы шаблона тут проста. [A-Z] - означает любые заглавные буквы латиницы. Следующий за ним квантор {3} говорит о том, что нам важно, чтобы таких букв было именно три. После дефиса мы ждем три цифровых разряда, поэтому добавляем на конце \d{3}
Денежные суммы
Похожим на предыдущий пункт образом, можно вытаскивать и цены (стоимости, НДС...) из описания товаров. Если денежные суммы, например, указываются через дефис, то:
Паттерн \d с квантором + ищет любое число до дефиса, а \d{2} будет искать копейки (два разряда) после.
Если нужно вытащить не цены, а НДС, то можно воспользоваться третьим необязательным аргументом нашей функции RegExpExtract, задающим порядковый номер извлекаемого элемента. И, само-собой, можно заменить функцией ПОДСТАВИТЬ (SUBSTITUTE) в результатах дефис на стандартный десятичный разделитель и добавить двойной минус в начале, чтобы Excel интерпретировал найденный НДС как нормальное число:
Автомобильные номера
Если не брать спецтранспорт, прицепы и прочие мотоциклы, то стандартный российский автомобильный номер разбирается по принципу "буква - три цифры - две буквы - код региона". Причем код региона может быть 2- или 3-значным, а в качестве букв применяются только те, что похожи внешне на латиницу. Таким образом, для извлечения номеров из текста нам поможет следующая регулярка:
Время
Для извлечения времени в формате ЧЧ:ММ подойдет такое регулярное выражение:
После двоеточия фрагмент [0-5]\d, как легко сообразить, задает любое число в интервале 00-59. Перед двоеточием в скобках работают два шаблона, разделенных логическим ИЛИ (вертикальной чертой):
- [0-1]\d - любое число в интервале 00-19
- 2[0-3] - любое число в интервале 20-23
К полученному результату можно применить дополнительно еще и стандартную Excel'евскую функцию ВРЕМЯ (TIME), чтобы преобразовать его в понятный программе и пригодный для дальнейших расчетов формат времени.
Проверка пароля
Предположим, что нам надо проверить список придуманных пользователями паролей на корректность. По нашим правилам, в паролях могут быть только английские буквы (строчные или прописные) и цифры. Пробелы, подчеркивания и другие знаки препинания не допускаются.
Проверку можно организовать с помощью вот такой несложной регулярки:
По сути, таким шаблоном мы требуем, чтобы между началом (^) и концом ($) в нашем тексте находились только символы из заданного в квадратных скобках набора. Если нужно проверить еще и длину пароля (например, не меньше 6 символов), то квантор + можно заменить на интервал "шесть и более" в виде {6,}:
Город из адреса
Допустим, нам нужно вытащить город из строки адреса. Поможет регулярка, извлекающая текст от "г." до следующей запятой:
Давайте разберем этот шаблон поподробнее.
Если вы прочитали текст выше, то уже поняли, что некоторые символы в регулярных выражениях (точки, звездочки, знаки доллара и т.д.) несут особый смысл. Если же нужно искать сами эти символы, то перед ними ставится обратная косая черта (иногда это называют экранированием). Поэтому при поиске фрагмента "г." мы должны написать в регулярке г\. если ищем плюсик, то \+ и т.д.
Следующих два символа в нашем шаблоне - точка и звездочка-квантор - обозначают любое количество любых символов, т.е. любое название города.
На конце шаблона стоит запятая, т.к. мы ищем текст от "г." до запятой. Но ведь в тексте может быть несколько запятых, правда? Не только после города, но и после улицы, дома и т.д. На какой из них будет останавливаться наш запрос? Вот за это отвечает вопросительный знак. Без него наша регулярка вытаскивала бы максимально длинную строку из всех возможных:
В терминах регулярных выражений, такой шаблон является "жадным". Чтобы исправить ситуацию и нужен вопросительный знак - он делает квантор, после которого стоит, "скупым" - и наш запрос берет текст только до первой встречной запятой после "г.":
Имя файла из полного пути
Еще одна весьма распространенная ситуация - вытащить имя файла из полного пути. Тут поможет простая регулярка вида:
Тут фишка в том, что поиск, по сути, происходит в обратном направлении - от конца к началу, т.к. в конце нашего шаблона стоит $, и мы ищем все, что перед ним до первого справа обратного слэша. Бэкслэш заэкранирован, как и точка в предыдущем примере.
P.S.
"Под занавес" хочу уточнить, что все вышеописанное - это малая часть из всех возможностей, которые предоставляют регулярные выражения. Спецсимволов и правил их использования очень много и на эту тему написаны целые книги (рекомендую для начала хотя бы эту). В некотором смысле, написание регулярных выражений - это почти искусство. Почти всегда придуманную регулярку можно улучшить или дополнить, сделав ее более изящной или способным работать с более широким диапазоном вариантов входных данных.
Для анализа и разбора чужих регулярок или отладки своих собственных есть несколько удобных онлайн-сервисов: RegEx101, RegExr и др.
К сожалению, не все возможности классических регулярных выражений поддерживаются в VBA (например, обратный поиск или POSIX-классы) и умеют работать с кириллицей, но и того, что есть, думаю, хватит на первое время, чтобы вас порадовать.
Если же вы не новичок в теме, и вам есть чем поделиться - оставляйте полезные при работе в Excel регулярки в комментариях ниже. Один ум хорошо, а два сапога - пара!
Ссылки по теме
- Замена и зачистка текста функцией ПОДСТАВИТЬ (SUBSTITUTE)
- Поиск и подсветка символов латиницы в русском тексте
- Поиск ближайшего похожего текста (Иванов = Ивонов = Иваноф и т.д.)
Знать - хорошо..
Уметь донести = бесценно. 8)
RegExpExtract у Вас возвращает String, а CVErr возвращает Variant.
Может сделать:
?
Когда-то давно нужно было и до сих пор ежегодно пользуюсь вытаскиваем индексов (6 подряд идущих цифр). Один наш контрагент имеет привычку скидывать Word файл с более чем 200 адресами типа "Организация, Индекс, Адрес, Телефон", а нужно было всё это расцепить.
Потом уже с установкой 2013 Excel вытаскивать индекс стало можно делать встроенной функцией "Мгновенное заполнение" (FlashFill).
Еще на форуме просил дать почитать об этом где-нибудь, вот такую дали ссылку:
Также с такого рода задачами по вытаскиваю какого-то шаблонного текста помогает PowerQuery функцией "Column from Examples".
Логично поддержка регулярных выражений могла быть встроена в Power Query , но я так и не нашёл встроенной функции «RegExp» в языке «М»..
Подскажите, а если, например, такой вариант "Текст-первый ТП-1 5900*2400" то как должно выглядеть регулярное выражение если нужно вытащить только 5900*2400? У меня только 5900 получилось (вот так в формуле ;2 а в устойчивом выражении /d{4}). Спасибо
\d{4}\*\d{4} - я, до того как вопрос задать, сидел и думал как самому сделать формулу. Строил такую же конструкцию, но она почему-то не работала ((
Удивительное совпадение, эта новость очень вовремя! Только вчера ломал голову как с помощью прав и левсимв вытаскивать габариты:like:
Но важно поймать системность в наборе данных. От этого зависит какой будет регулярка.
Только не пойму как написать регулярку, для того чтобы извлечь из строки типа: "что-то_там" : [ 1, 0, 3, 2, 5, 4, 6 ]
только цифры??
\d*
Есть еще один вопросик, если не сложно.
У меня задача выдергивать куски текста между заданными словами, причем эти слова исключая, ну, например:
Текст
Record type: Noncompliance Issue
Status: Closed
Originator: Volodymyr
Должно получиться Closed
При чем в тексте присутствуют как знаки табуляции так и перевода строки.
И в общем случае возможно, что нужный фрагмент состоит из нескольких строк.
Что я опять не так сделал?
Excel 2016.
Нет и в примере не работает.
(P.S. Ха-ха, что называется зарапортовался. Назвал Вас Павлом.))) Работая в эксель, параллельно слушал Ю.Болдырева, его агитацию за Павла, который Грудинин, ну, вот и ... Короче, исправил.)
Почему в вашем примере все работает, а создаю новую книгу, заношу в редактор VBA тот же самый текст. Делаю все тоже в книге в тех же ячейках. Результат #ЗНАЧ. Что только не пробовал. Не могу понять. Поясните, пожалуйста.
username@site.somelongzone
, второе - такого:
user-name@site.ru
А ведь и то, и другое встречается в реальном мире.
Вот ещё, на десерт:
username@я-вообще-то-тоже-сайт.рф
p.s.: по всем смыслам кошерная регулярка на валидность email'а выглядит как длинющиий паровоз. Оставьте
Все разрешения даны, всё включено, но никак не хочет работать. Есть какая-нибудь подсказка?
Dim regex As RegExp
Dim matches As Object
После этого заработало.
Но есть проблема: модуль с функцией находится в Personal, первый раз всё сработало на ура, но при создании новой книги функцию excel не распознаёт.
Подскажите, пожалуйста, как сделать, чтобы всё работало?
Ссылку на скрин экрана прилагаю:
cloud.mail.ru/public/JYbd/R1suJRZde
Спасибо!
123456, СК обл., г. Ставрополь, село Приморское, хутор. Волянский,,,,,
ул. Малиновая, д.81 кв.21, проезд 4, стр. 7, квартал 554, корпус 11, а/я 78
На втором заменить результат, найденный предыдущей операцией на одну запятую формулой "подставить": =ПОДСТАВИТЬ(A1;B1;","), где вместо А1 написать адрес исходный текст, а вместо B1 - ячейку с формулой RegExpExtract, в которой использовалось указанное регулярное выражение..
Ctrl+H вам в помощь.
Для второго: ,[^,]+
Правда, во втором случае в ответ войдёт запятая...
Вообще же можно использовать функции ПРАВСИМВ и ЛЕВСИМВ. Для первого случая формула: ЛЕВСИМВ(A1;ПОИСК(",";A1)-1) для второго: ПРАВСИМВ(A1;ДЛСТР(A1)-ПОИСК(",";A1)-1) (соответственно понятно, вместо A1 написать адрес ячейки, в которой расположено выражение "K1-0101, K1-0102").
А, вот сообразила как без ПРАВСИМВ и ЛЕВСИМВ исключить запятую во втором случае: [^, ]+$
заодно узнаём о полезных свойствах круглых скобочек))
Вот пример текста:
Пишете в текстовом поле регулярку, жмете кнопку "Display" - регулярка отображается в виде блок-схемы. Чудеса!
Однако есть вопрос по отрицанию, как вырезать все от слова до конца, либо до стоп-слова, если есть.
Например, ячейки с текстом:
Кресло AB2-34-6 ABCD цвет: ABCD (АБВГ)
цвет: ABC (АБВ)
цвет: ABCD (АБВГ)
Похоже решили:
цвет.*(?=\(по.*) - так он вытаскивает из первой строки
В конце пробел.
Если надо применить к целому столбцу, то копируйте потом вниз на 10 ячеек - и все.
[А-Я а-я]*ул.
И зачем последний пробел? Вроде и без него работает.
Спасибо ))
[^ ]+(?= ул\.)
Re: ЭДО проблемы_ АЙСБИТ ЗАО (РЦ) YB03412300
Вывести только АЙСБИТ ЗАО ?
Спасибо
Шаблон [^ЖМ]уть никак не найдёт слово Забудь (если только его не написать как "забуть";).
С помощью RegExp и функции подставить получил ячейку со значениями в виде 316;78;230;750;302;100. Как теперь Эти значения можно просуммировать? Если ставлю функцию сумм в начале формулы, то excel выдает ошибку, так как эти числа получаются как текст.
Требуется организация цикла, надо знать общее количество значений...
Предлагаю Вам самостоятельно реализовать другую функцию (на базе упомянутой), назвав ее, например, так: RegExpExtractAll().
Эта функция должна возвращать массив значений (результат поиска).
Как-то так:
Function RegExpExtractAll(Text As String, Pattern As String)
Dim arr() As String
Dim re As Object
Dim matches As Object
Dim i&
Set re = CreateObject("VBScript.RegExp")
re.Pattern = Pattern
If re.Test(Text) Then
Set matches = re.Execute(Text)
ReDim arr(matches.Count - 1)
For i = 0 To UBound(arr)
arr(i) = matches(i)
Next
If UBound(arr) = 0 Then
RegExpExtractAll = arr(0)
Else
RegExpExtractAll = arr()
End if
Exit Function
End If
Failed:
RegExpExtractAll = CVErr(xlErrValue)
End function
Потребуется только преобразовать значения к числовому виду и сложить их.
Введите формулу: =СУММПРОИЗВ(--RegExpExtractAll(Text;"\d+"))
ИЛИ
Введите формулу массива: {=СУММ(RegExpExtractAll(Text;"\d+")*1)}
где Text – это ваша строка "316;78;230;750;302;100" или ссылка на ячейку, содержащую строку данных.
Примечания:
1. Использование двойного унарного оператора (двух знаков минус вместе) приводит к преобразованию текста в число без изменения знака числа.
С таким же успехом вместо этого можно вставить формулу ЦЕЛОЕ(), просто будет длиннее.
Введите формулу: =СУММПРОИЗВ(ЦЕЛОЕ(RegExpExtractAll(Text;"\d+")))
2. Умножение на единицу также приводит к преобразованию текста в число.
3. Формула СУММПРОИЗВ() здесь оперирует только одним множителем (массивом), значения которого преобразуются к численному типу данных, т.е. ничего не перемножается (единственный аргумент), а фактически выполняется только сложение преобразованных значений массива.
' После присвоения значения функции:
RegExpExtractAll = arr()
' Вставьте следующий блок, ориентирующий массив в зависимости от выбранного вами диапазона ячеек для приема значений:
With Application
If TypeName(.Caller) = "Range" Then
' Test if it is being called from a row vector.
If .Caller.Rows.Count > 1 Then
RegExpExtractAll = .Transpose(arr)
End If
End If
End With
где Caller в данном случае и есть тот самый многоячеечный диапазон, из которого осуществлен вызов функции RegExpExtractAll(). Очевидно, что формулы могут быть введены заранее, только если вы работаете с каким-то фиксированным массивом, размер которого вам известен.
Примечание. Формула будет одна, вводится она в диапазон ячеек как формула массива (заключается в фигурные скобки).
Попробуйте извлечь:
Text:="two words"
Pattern:="^|\w+" 'Пустая строка в начале строки или слово (лат.)
Item:=2
=RegExpExtract("two words";"^|\w+";2)
Результат: wo
MatchCollection: {"";"wo";"words"} <-- Обратите внимание на пропущенную букву t
мне нужно получить 1/2/3
регуляркой (.*)/ получаю 1/2/3/
хотя по идее должен отдавать то что в скобках, то есть 1/2/3
Можно как-то получать то что в скобках через $1 $2 и т.п.?
(.*)\/
Зд. я экранировал слэш (в Excel не обязательно, хотя это хорошая практика),
regex101 показывает, что всё решается за 13 шагов (42 ms).
И выше, и у вас всё правильно! То, что в скобках отдает при ссылке по $1, а полный результат включает слэш, т.к. он присутствует в вашем шаблоне.
Для анализа выражения использован ресурс
Проблема в том, что через эту функцию(для экселя) не могу получить значение группы. Только полное соответствие Full match.
А последний параметр функции позволяет выбрать какой из Full mutch брать, например:
Данные: 1/2/3/выв
регулярка: \/
Match 1
Full match 1-2 `/`
Match 2
Full match 3-4 `/`
Match 3
Full match 5-6 `/`
Хочется возможность выбора группы в функции.
Последний параметр позволяет выбрать один из результатов поиска -- это первый уровень иерархии (Match Object). Группы, только если они выделены, вложены в каждый из таких результатов -- второй уровень иерархии (Matches Collection). У вас все "мэчи" полные (full match), потому что они другими не бывают. Но даже если выделить группу, используя круглые скобки (происходит захват), то всё равно вы не сможете к ней обратиться. В самом шаблоне сослаться на группу вы однако можете через синтаксис \1 (именно так: через бэкслэш), но это не то, что вам надо. К вашей задаче это не имеет никакого отношения.
Результатов поиска может быть много, как слов в предложении. Но можно разбить каждое слово, например на буквы, и тогда в каждом слове-поиске будет по несколько выделенных букв-групп. Как-то так. Но зачем вам это? Автор одной функцией вон сколько задач решил!
Попробуйте вот такой шаблон (regex101 не находит ничего, но VBScript справляется):
^.*(?=/[^/]*)$
Пояснение. В пределах строки от начала ^ до конца $ найти последовательность любых символов .* перед набором символов, состоящим из одного слэша / и последовательности, наоборот, из любых символов, кроме слэша [^/]*. Всё, что в круглых скобках есть группа (look ahead -- вперед смотрящий), читайте руководство.
Функция автора RegExpExtract() не дает возможности ссылаться на группы. То, что в круглых скобках в шаблоне, есть действительно группа, но возможность работать с такой группой предоставляет метод RegExp.Replace(), который в функции автора не используется.
Реализуйте свою функцию RegExpReplace(Text, Pattern, Replace), в тело которой вставьте метод RegExp.Replace(Text, Replace).
Функция будет не длиннее, чем первая. Всё просто.
Text -- это исходный текст,
Replace -- строка (с использованием шаблонов ссылок типа $1), которой надо заменить в исходной строке Text результат поиска по шаблону Pattern.
Для того, чтобы было удобно производить замены, желательно найти всю строку целиком и выделить в ней требуемые группы.
В наше случае вот так:
(.*)/.*
RegExpReplace("1/2/3/выв";"(.*)/.*";"№$1")
Возвращаемый результат будет таким:
№1/2/3
Но если вы хотите заменить подстроку или, еще лучше, удалить ее совсем в исходном тексте, то тогда так:
RegExpReplace("1/2/3/выв";"(.*)/";"")
Возвращаемый результат будет таким (результатом поиска по шаблону будет "1/2/3/"):
выв
Сослаться на группу при манипуляции со строками (не в шаблоне) вы можете через синтаксис $1 (именно так: через знак доллара).
Если я вас правильно понял.
Если вам нужны не манипуляции с подстроками путем замены, то следуйте правилу:
пишите шаблоны (рег. выражение) так жестко, чтобы находилось (извлекалось) только что-то одно или же делайте несколько вызовов по более общему шаблону, но указывайте, какой результат по порядку (параметр Item) надо вернуть. Результаты самостоятельных вызовов функции объединяйте, обрабатывайте и пр. По большому счету, можно оперировать результатами поиска как вашими группами (только без ссылок типа $).
^.*(?=/[^/]*$)
Интересный прием выше хорошо описан на англ. языке по ссылке ниже (см. раздел "Condition 2"):
Шаблон
/[^/]*
является примером принципа контраста, рекомендованного руководством по регулярным выражениям (
У меня редактор VBA ругается на $1...
=RegExpExtract("1/2/3/выв";"^.*(?=/[^/]*$)")
Возвращает: 1/2/3
На этом сайте нет ни одной чужой статьи.
Осмелюсь предположить, что скопировали у меня - это часто бывает и не всегда с указанием авторства, к сожалению.
Пробежал по контенту, а там тупо все посты с Вашего сайта. Олень какой-то.
Еще раз приношу глубочайшие.
А за статью спасибо огромное!
И спасибо на добром слове
У меня вопрос, похоже в тему. Прошу совет, как реализовать.
Я периодически являюсь модератором чата во время определенного вебинара.
Среди кучи пустой болтовни в чате, периодически люди сбрасывают туда свои телефоны. Это - подтверждение того, что им интересен продукт. о котором говорится в вебинаре и просят с ними связаться.
Вот, на сегодняший день я просто визуально ищу среди тысячи сообщений 20 телефонов.
Очень хотел бы упростить жизнь каким-то функционалом Excel/
Т.е. еще раз у меня есть столбец, содержащий очень разную информацию:
- плюсики, когда спикер спрашивает, слышно ли его
- какие-то выборочные цифры, когда спикер просит написать такую-то цифру, если у людей был такой-то случай
- текст, когда люди задают вопросы спикеру или текстом отвечают на его вопросы
- номера телефонов (вот это то что мне нужно достать)
- смешанныне поля, когда в одном сообщении и номер телефона и какой-то комментарий, что человека интересует такой-то блок продаваемого тренинга.
Вот, хотелось бы справа вставить какую-то формулу, раскопировать вниз по всей тысяче строк-сообщений. И чтобы в этом втором столбце остались только номера телефонов, которые формула достала.
Реализуемо ли? и если да. то как? опять же учитывая, что люди пишут номера кто как.
Спасибо!
"КОМПАНИЯ ООО / В том числе НДС 18%, 9599.00 руб. №1111 №2222, 3333 от 11.11.2018 N4444 N 5555,6666 сч7777 от 11.11.2018 сч 8888 сч.9999 сч. 1010 счетам 1100 и счету 1200 НДС 18%, 99999.99 руб"
Имея такую регулярку [#N№мтуч\.,](\s\d{3,4}|\d{3,4})(?=\D) мне выдает следующее:
"9599,1111,2222, 3333,2018,4444, 5555,6666,7777,2018, 8888,9999, 1010, 1100, 1200"
Вопрос если мне нужно захватывать такие вот выражения "сч.9999 сч. 1010" с точкой, как избежать попадания дат и сумм? если я уберу из регулярки "\." то меня спасает от даты и сумм "(?=\D)", но тогда под маску не попадают нужные мне данные.
Составил список с названиями файлов,
369 1234 RP - 2001.02.11 15-55 (2500).xlsx из этой ячейки мне надо вытащить 1234 и (2500).
Из примера понятно что 1234 можно взять этим способом \d{4}. А как соединить 1234 и (2500) ???
Составил список с названиями файлов,
369 1234 RP - 2001.02.11 15-55 (2500).xlsx из этой ячейки мне надо вытащить 1234 и (2500).
Из примера понятно что 1234 можно взять этим способом \d{4}. А как соединить 1234 и (2500) ???
=RegExpExtract(Text;"\d{4}") & " " & RegExpExtract(Text;"\(\d{4}\)").
Примечание. Вы можете объединить паттерн и вызывать функцию с указанием, какой элемент извлечь:
Pattern = "\d{4}|\(\d{4}\)" <- Так будет удобнее редактировать паттерн (при необходимости)
=RegExpExtract(Text;Pattern;1) & " " & RegExpExtract(Text;Pattern;2)
Но: всё работает при условии, что первой части критерия ("\d{4}") отвечает один результат в исходном тексте.
Не тестировал.
попытался в лоб использовать ее в своем макросе, но отладчик ругается, если задаю параметры переменными... Compile error: ByRef argument type mismatch! переменные строковые, объявленные...можно тут что-то сделать? Спасибо
(Договор № 5000/316 от 01.11.2016 г.) 5000/316
2413 от 01.08.2007
от 01.08.2013 № 9
RegExp шаблон: \d+/?\d*(?= от)|\d+$
\d+/?\d*(?= от) это цифры (\d+), после которых может идти символ "/", а может и не идти (/?),
далее могут быть ещё цифры, а могут и не быть (\d*) -
и всё это перед символами " от" (случай 1 и 2)
\d+$ это цифры в конце строки (случай 3)
=RegExpExtract(Text;"\d+/?\d*(?= от)|\d+$")
P.S. При слабой стандартизации входных данных будет работать всё равно не надёжно. Но для приведенных Вами примеров подойдёт. Очень жёстко!
RegExp шаблон: \d+/?\d*(?= *от)|\d+ *$ <-- Здесь добавлена звёздочка после пробела перед "от)" и звёздочка с пробелом в конце строки перед "$", это делает схему более "мягкой" при наличии "лишних" пробелов в тексте.
Добрый день! Просьба помочь с вопросом.
С помощью RegExp и функции подставить получил ячейку со значениями в виде 316;78;230;750;302;100. Как теперь Эти значения можно просуммировать? Если ставлю функцию сумм в начале формулы, то excel выдает ошибку, так как эти числа получаются как текст.
В этом варианте нужно вводить маску в ячейку
В этом варианте маска по умолчанию "\d+"
Немного ещё поковырялся и вот, что получилось
Если разделитель (Razdel) опущен то "; ". Если разделитель числовое значение, то в начале и конце добавляется пробел.
Если Deistvie = 1 то суммирует все числовые значения, что не распознал как число дописывает в конце через разделитель.
Если Deistvie <> 1 или опущен то собирает все значения через разделитель.
Сохранил как ".xlam" с пояснениями к аргументам, но к сожалению здесь нельзя его выложить