Страницы: 1
RSS
Извлечения данных из скобок, Извлечение данных из нескольких пар разделителей с помощью регулярных выражений или другими способами
 
Добрый день, уважаемые Планетяне! Название темы такое выбрано для облегчения поиска.
Впоследствии на эту тему можно будет ссылаться, т.к. решение должно получиться универсальным  :idea:
Вот здесь я влез в чужую тему с попыткой разобраться в возможностях применения RegExp для решения моей задачи. Ребята мне (и надеюсь не только мне) очень помогли - родилось 2 универсальные функции на регулярках: замена и извлечение. Долгое время этого хватало, но теперь, когда настало время извлечения данных из текста другого форматирования, появились проблемы.

В файле-примере подробное описание проблемы, текущая ситуация и желаемый результат.

Прошу помощи в решении…

07.06.2016. Найденные решения — в посте #19 ;)
Изменено: Jack Famous - 16.09.2016 19:28:37
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Доброе время суток
Jack Famous, честно говоря не понял пример, то ли вы хотите удалить переносы строки (тогда удаляете \n\r), то ли извлечь текст с квадратными скобками, тогда \[.+?\] для извлечения.
 
Код
Function QQ(s$)
    With CreateObject("VBScript.RegExp")
        .Global = True
        .IgnoreCase = False
        .MultiLine = False
        .Pattern = "(?:\(|\[)(.+?)(?:\)|\])"
        If .Test(s) Then
            For Each sM In .Execute(s)
                ss = ss & Chr(10) & sM.SubMatches(0)
            Next
            QQ = Mid(ss, 2)
        End If
    End With
End Function
 
Здравствуйте, Андрей VG! :) удалить переносы мне проще через Ctrl+H. Слева от текста находятся КРУГЛЫЕ скобки, справа - КВАДРАТНЫЕ.
Ваш шаблон работает только если каждая пара скобок отделена хотя бы одним ПЕРЕНОСОМ (разрывом) строки и был изначально в примере.
RAN,  всё работает (причём с любым количеством пар, вроде) - спасибо огромное!
Кстати, можно было ИЛИ не использовать, т.к. ВСЕГДА слева круглые скобки, а справа квадратные, но на будущее усёк))))  :idea:

Осталась ещё пара вопросов:
1. как НЕ извлекать разделители (то есть скобки слева и справа, в данном случае)
2. как исправить НЕрегулярную UDF (есть в файле, чтобы точно также работала)

P.S.: пользовался ТОЛЬКО шаблонами, используя универсальную UDF из файла. Заменил файл-пример в заголовке темы. Дублирую тут…
Изменено: Jack Famous - 03.06.2016 16:01:43
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
можно было ИЛИ не использовать, т.к. ВСЕГДА слева круглые скобки, а справа квадратные
Кто-то говорил про универсальность ))
 
Я вот так и знал - вот прямо чувствовал, что кто-то подколет по "моей" теме  :D))))))
Юрий М, это решение для извлечения всех вхождений данных между 2мя ВСЕГДА попарно одинаковыми разделителями (то есть, например, извлечь все данные из "контейнеров", ограниченных слева "пробелом", а справа ";". Очень хорошо это иллюстрирует НЕрегулярная UDF из примера - она как раз под это заточена.
А вариант RAN, существенно расширяет границы извлечения и, безусловно, будет жизненно необходим при более рандомных условиях  :idea:

К тому же, в подавляющем большинстве вопросов по этой теме на форуме необходимо как раз ЭТО (буду сюда отправлять), а более-менее длинные шаблоны для RegExp не вызывают желания понять суть их работы и являются разовыми решениями (опять же - для большинства из задающих вопросы)  ;)
Изменено: Jack Famous - 03.06.2016 16:00:34
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
1. как НЕ извлекать разделители (то есть скобки слева и справа, в данном случае)
Вполне достаточно не портить рабочий макрос.
 
RAN, не совсем понял, что конкретно вы имеете ввиду. Дело в том, что UDF (не на регулярках), извлекающая данные между двумя разделителями действительно извлекает без разделителей, НО только ПЕРВОЕ вхождение. В то же время, UDF на регулярках извлекает ВСЕ вхождения, однако и разделители цепляет...
а короче говоря:
1. Извлекает, как надо, но только первое
2. Извлекает всё, что нужно, но результат извлечения нуждается в дополнительной очистке

Я, конечно, надеюсь, что в итоге кто-нибудь из VBA-мастеров сделает (или скажет, где это уже решено) UDF или макрос, в которой(ом) нужно будет указать 2 разделителя (начальный и конечный), а также разделитель сцепления (через что будет сцеплено найденное) - считаю этот вариант самым  оптимальным в использовании, но не знаю, насколько он труден в исполнении. А пока - только регулярками)))))
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, UDF на регулярках уважаемого RAN  не цепляет разделителей
Соблюдение правил форума не освобождает от модераторского произвола
 
RAN, прошу прощения...не понял)))) как и написал - использовал ТОЛЬКО шаблон для UDF «ВзятьРегулярками» из примера (в таком случае, разделители остаются).
Добавлю ВАШУ UDF в коллекцию  ;) - огромное спасибо!!!  8) :idea:  
Также большое спасибо, buchlotnik, за подсказку! :excl: :idea:   - я-то решил, что RAN, имел ввиду нерегулярную функцию «ВзятьИзРазделителей» из примера  :D
Изменено: Jack Famous - 06.06.2016 16:10:37
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Кто-нибудь, подскажите, как внутрь шаблона "засунуть" переменные del1 и del2, которые будут указываться в функции (со знаком сцепления я разберусь)  :)
Что-то типа .Pattern = "(?:del1)(.+?)(?:del2)" - но это, естественно, не сработает, как надо))))
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
.Pattern = "(?:" & del1 & ")(.+?)(?:" & del2 &")"
или если используются служебные символы:
.Pattern = "(?:\" & del1 & ")(.+?)(?:\" & del2 &")"  
Изменено: buchlotnik - 06.06.2016 16:24:42
Соблюдение правил форума не освобождает от модераторского произвола
 
buchlotnik, чёт никак  :(
Изменено: Jack Famous - 06.06.2016 16:38:03 (Перезалил пример)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Код
чёт никак 
где файл с никак?

кому вообще решение нужно?
Код
Function reg_del(t$, d1$, d2$)
    With CreateObject("VBScript.regexp")
        .Global = True
        .Pattern = "(?:\" & d1 & ")(.+?)(?:\" & d2 & ")"
        If .Test(t) Then
            For Each sM In .Execute(t)
                ss = ss & Chr(10) & sM.SubMatches(0)
            Next
            reg_del = Mid(ss, 2)
        End If
    End With
End Function
файл перезалил - так нагляднее
Изменено: buchlotnik - 06.06.2016 16:48:28
Соблюдение правил форума не освобождает от модераторского произвола
 
Jack Famous,
Цитата
Перезалил пример
издеваетесь? вы переименовали del1 и del2 в del_begin и del_finish, паттерн при этом заменить не потрудились
и да - точка перед Pattern тоже значение имеет
Изменено: buchlotnik - 06.06.2016 16:55:51
Соблюдение правил форума не освобождает от модераторского произвола
 
buchlotnik, не издеваюсь…косячнул, т.к. поторопился… Изменял, т.к. мне удобнее. Ваш пример отлично работает. Убрал "\" из константы - при необходимости буду в переменной указывать.
Всё работает - спасибо вам большое!  :idea:
Код
'Вытащить значения между двумя разделителями (несколько вхождений)
'Особенность: Используются регулярные выражения. В переменных del1 и del2 при необходимости указывать "\". Если указать в качестве знака сцепления "перенос", то будет использован перенос строки
'Автор: RAN
'Главный редактор: buchlotnik (сделал UDF универсальной)
'Тема на форуме: http://www.planetaexcel.ru/forum/index.php?PAGE_NAME=message&FID=1&TID=78513&TITLE_SEO=78513-izvlecheniya-dannykh-iz-skobok&MID=657681&result=edit#postform
'==================================================================================================================================================================================================
Function ВзятьИзРазделителейРегулярками(cell$, del1$, del2$, del_merge$)

If del_merge = "перенос" Then del_merge = Chr(10)

    With CreateObject("VBScript.regexp")
        .Global = True
        .Pattern = "(?:" & del1 & ")(.+?)(?:" & del2 & ")"
        If .Test(cell) Then
            For Each sM In .Execute(cell)
                ss = ss & del_merge & sM.SubMatches(0)
            Next
            ВзятьИзРазделителейРегулярками = Mid(ss, Len(del_merge)+1)
        End If
    End With
End Function


Изменено: Jack Famous - 07.06.2016 10:57:23 (стыдоба))))
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
buchlotnik (сделал UDF универсальной)
ну раз пошла такая пьянка, то потрудитесь исправить
Код
ВзятьИзРазделителейРегулярками = Mid(ss, 2)
на
Код
ВзятьИзРазделителейРегулярками = Mid(ss, Len(del_merge)+1)
Соблюдение правил форума не освобождает от модераторского произвола
 
Доброе время суток
Вариант без регулярных
Код
Public Function GetInternals(ByVal Text As String, ByVal Delimiter As String, _
                             ByVal leftSign As String, ByVal rightSign As String) As String
    Dim leftPos As Long, rightPos As Long, sOut As String
    Dim leftLen As Long, rightLen As Long
    
    leftLen = Len(leftSign): rightLen = Len(rightSign)
    sOut = "": rightPos = -rightLen + 1
    Do
        leftPos = InStr(rightPos + rightLen, Text, leftSign, vbTextCompare)
        If leftPos = 0 Then Exit Do
        rightPos = InStr(leftPos + leftLen + 1, Text, rightSign, vbTextCompare)
        If rightPos = 0 Then Exit Do
        sOut = sOut & Mid$(Text, leftPos + leftLen, rightPos - leftPos - leftLen) & Delimiter
    Loop
    If Len(sOut) > Len(Delimiter) Then sOut = Left$(sOut, Len(sOut) - Len(Delimiter))
    GetInternals = sOut
End Function

Тест на 10000 проходах в цикле, лучшее время по 5 запускам 0,1855469
Для сравнения ВзятьИзРазделителейРегулярками - 1,808594
Успехов.
 
buchlotnik, точно - я же изменил перенос строки на переменную  :oops:...стыдоба))))) спасибо большое!!! - только начинаю вникать… Тело макроса поправил  ;)
Андрей VG, огромное спасибо за НЕрегулярное решение проблемы!  :idea: 8) я-то уже начал инструкцию писать для краткого ознакомления с синтаксисом RegExp (когда применять «\» а когда нет)))))

16.09.2016. Чуть приукрасил для удобства использования
Вариант с регулярками: от RAN и buchlotnik
НЕрегулярное решение от Андрей VG:
Изменено: Jack Famous - 07.09.2017 10:44:32
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Страницы: 1
Читают тему
Наверх