AZJIO
Сейчас трудно вспомнить. Может что-то типа этого?
EnableExplicit ImportC "" ;pb_pcre_exec(*pcre, *extra, subject.p-utf8, length, startoffset, options, *ovector, ovecsize) pb_pcre_exec(*pcre, *extra, *subject, length, startoffset, options, *ovector, ovecsize) EndImport ;========================================================================================================================== Procedure.s RegexReplace1( Regex, Subject.s, Replacement.s ) Protected Dim ovec(30) ; для MaximumReference = 9 Protected GroupBegin, GroupEnd, GroupCount, GroupNumber, Offset Protected Result.s, Replacing.s Protected SubjectLength = StringByteLength(Subject,#PB_UTF8) Protected SubjectBuffer = AllocateMemory(SubjectLength+1,#PB_Memory_NoClear) PokeS(SubjectBuffer,Subject,-1,#PB_UTF8) While Offset < SubjectLength ; будем вызывать pb_pcre_exec, пока не закончится строка ; -1 - не нашли; 1 - совпадение; >1 - совпадение и группы GroupCount = pb_pcre_exec(PeekL(Regex),0,SubjectBuffer,SubjectLength,Offset,0,ovec(),ArraySize(ovec())) - 1 If GroupCount >= 0 Replacing = Replacement For GroupNumber=0 To 9 ; извлекаем группы и заменяем обратные ссылки GroupBegin = ovec(GroupNumber*2) GroupEnd = ovec(GroupNumber*2+1) ; Если группы нет, то в ovec будут нули и PeekS вернёт пустую строку Replacing = ReplaceString(Replacing,"\"+Str(GroupNumber),PeekS(SubjectBuffer+GroupBegin,GroupEnd-GroupBegin,#PB_UTF8)) Next ; ovec(0) - начало совпадения, ovec(1) - конец совпадения ; Result + часть строки между началом и первым совпадением или между двумя совпадениями + результат подстановки групп Result + PeekS(SubjectBuffer+Offset,ovec(0)-Offset,#PB_UTF8) + Replacing Offset = ovec(1) Else ; больше ничего не найдено или вообще ничего не найдено ; Result + остаток строки Result + PeekS(SubjectBuffer+Offset,SubjectLength-Offset,#PB_UTF8) Break EndIf Wend FreeMemory(SubjectBuffer) ProcedureReturn Result EndProcedure ;========================================================================================================================== Procedure.s RegexReplace2( Regex, Subject.s, Replacement.s ) Protected GroupNumber, GroupCount, MatchPos, Offset=1 Protected Replacing.s, Result.s If ExamineRegularExpression(Regex,Subject) While NextRegularExpressionMatch(Regex) MatchPos = RegularExpressionMatchPosition(Regex) Replacing = ReplaceString(Replacement,"\0",RegularExpressionMatchString(Regex)) ; обратная ссылка \0 GroupCount = CountRegularExpressionGroups(Regex) If GroupCount>9 : GroupCount=9 : EndIf ; только обратные ссылки \1 .. \9 For GroupNumber=1 To GroupCount Replacing = ReplaceString(Replacing,"\"+Str(GroupNumber),RegularExpressionGroup(Regex,GroupNumber)) Next For GroupNumber=GroupCount+1 To 9 ; отсутствующие группы на пустые строки Replacing = ReplaceString(Replacing,"\"+Str(GroupNumber),"") Next ; Result + часть строки между началом и первым совпадением или между двумя совпадениями + результат подстановки групп Result + Mid(Subject,Offset,MatchPos-Offset) + Replacing Offset = MatchPos+RegularExpressionMatchLength(Regex) Wend ProcedureReturn Result + Mid(Subject,Offset) ; Result + остаток строки EndIf ProcedureReturn Subject ; без изменений EndProcedure ;========================================================================================================================== Procedure.s RegexReplace3( Regex, Subject.s, Replacement.s ) Protected Dim ovec(30) ; для MaximumReference = 9 Protected Dim Groups.s(9) Protected GroupBegin, GroupEnd, GroupCount, GroupNumber, Offset Protected RPos, ROffset, RLen=Len(Replacement) Protected Result.s, Replacing.s Protected SubjectLength = StringByteLength(Subject,#PB_UTF8) Protected SubjectBuffer = AllocateMemory(SubjectLength+1,#PB_Memory_NoClear) PokeS(SubjectBuffer,Subject,-1,#PB_UTF8) While Offset < SubjectLength ; будем вызывать pb_pcre_exec, пока не закончится строка ; -1 - не нашли; 1 - совпадение; >1 - совпадение и группы GroupCount = pb_pcre_exec(PeekL(Regex),0,SubjectBuffer,SubjectLength,Offset,0,ovec(),ArraySize(ovec())) - 1 If GroupCount >= 0 For GroupNumber=0 To 9 ; Извлекаем строку совпадения (\0) и группы (\1..\9). ; Если группы нет, то в ovec будут нули и PeekS вернёт пустую строку GroupBegin = ovec(GroupNumber*2) GroupEnd = ovec(GroupNumber*2+1) Groups(GroupNumber) = PeekS(SubjectBuffer+GroupBegin,GroupEnd-GroupBegin,#PB_UTF8) Next Replacing = "" RPos = 1 ROffset = 1 While RPos < RLen ; последний символ не обрабатываем Select Mid(Replacement,RPos,2) Case "\\" RPos + 2 Case "\0","\1","\2","\3","\4","\5","\6","\7","\8","\9" GroupNumber = Val(Mid(Replacement,RPos+1,1)) Replacing + Mid(Replacement,ROffset,RPos-ROffset) + Groups(GroupNumber) RPos + 2 ROffset = RPos Default RPos + 1 EndSelect Wend ; ovec(0) - начало совпадения, ovec(1) - конец совпадения ; Result + часть строки между началом и первым совпадением или между двумя совпадениями ; + результат подстановки групп ; + остаток строки замены Result + PeekS(SubjectBuffer+Offset,ovec(0)-Offset,#PB_UTF8) + Replacing + Mid(Replacement,ROffset) Offset = ovec(1) Else ; больше ничего не найдено или вообще ничего не найдено ; Result + остаток строки Result + PeekS(SubjectBuffer+Offset,SubjectLength-Offset,#PB_UTF8) Break EndIf Wend FreeMemory(SubjectBuffer) ProcedureReturn Result EndProcedure ;========================================================================================================================== Procedure.s RegexReplace4( Regex, Subject.s, Replacement.s ) Protected MatchPos, GroupNumber, GroupCount, Offset=1 Protected RPos, ROffset, RLen=Len(Replacement) Protected Replacing.s, Result.s, Spec.s If ExamineRegularExpression(Regex,Subject) While NextRegularExpressionMatch(Regex) MatchPos = RegularExpressionMatchPosition(Regex) GroupCount = CountRegularExpressionGroups(Regex) Replacing = "" RPos = 1 ROffset = 1 While RPos < RLen ; последний символ не обрабатываем Spec = Mid(Replacement,RPos,2) Select Spec Case "\\" RPos + 2 Case "\0" Replacing + Mid(Replacement,ROffset,RPos-ROffset) + RegularExpressionMatchString(Regex) RPos + 2 ROffset = RPos Case "\1","\2","\3","\4","\5","\6","\7","\8","\9" GroupNumber = Val(Mid(Spec,2)) Replacing + Mid(Replacement,ROffset,RPos-ROffset) If GroupNumber <= GroupCount ; существующая группа, иначе - пусто Replacing + RegularExpressionGroup(Regex,GroupNumber) EndIf RPos + 2 ROffset = RPos Default RPos + 1 EndSelect Wend ; Result + часть строки между началом и первым совпадением или между двумя совпадениями ; + результат подстановки групп ; + остаток строки замены Result + Mid(Subject,Offset,MatchPos-Offset) + Replacing + Mid(Replacement,ROffset) Offset = MatchPos+RegularExpressionMatchLength(Regex) Wend ProcedureReturn Result + Mid(Subject,Offset) ; Result + остаток строки EndIf ProcedureReturn Subject ; без изменений EndProcedure ;==========================================================================================================================
В новых версиях PB у меня внезапно начали глючить функции на основе pb_pcre_exec.
Но, слава богу, появилась возможность работать с группами.