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.
Но, слава богу, появилась возможность работать с группами.
