1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
| ; Для юникода! Сохранять в UTF8! 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 ;========================================================================================================================== Define rex, r.s, s.s r = "([abxy]+)..([abxy]+)" s = "!----aaa\1bbb----!----xyxyx\2yxyxy----!" rex = CreateRegularExpression(#PB_Any, r, #PB_RegularExpression_NoCase) Debug s Debug RegexReplace1( rex, s, "<\2===\0===\1><\4>" ) Debug RegexReplace2( rex, s, "<\2===\0===\1><\4>" ) Debug RegexReplace3( rex, s, "<\2===\0===\1><\4>" ) Debug RegexReplace4( rex, s, "<\2===\0===\1><\4>" ) |