2016-05-24 9 views
9

Из того, что я могу почерпнуть из документации Pharo на регулярное выражение, я могу определить объект регулярного выражения, такие как:Захват строки в замене регулярных выражений

re := '(foo|re)bar' asRegex 

И я могу заменить совпадающий регулярное выражение со строкой через это:

re copy: 'foobar blah rebar' replacingMatchesWith: 'meh' 

Это приведет к: «meh blah meh».

До сих пор так хорошо. Но я хочу заменить 'bar' и оставить префикс в покое. Поэтому, мне нужна переменная для обработки захваченный: в скобках

re copy: 'foobar blah rebar' replacingMatchesWith: '%1meh' 

И я хочу результат: 'foomeh blah remeh'. Однако это просто дает мне: '%1meh blah %1meh'. Я также пробовал использовать \1 или \\1, или $1, или {1} и получил замену литерала, , например., '\1meh blah \1meh' в результате.

я могу сделать это достаточно легко в GNU Smalltalk с:

'foobar blah rebar' replacingAllRegex: '(foo|re)bar' with: '%1meh' 

Но я нигде не могу найти в документации регулярных выражений Pharo, который говорит мне, как я могу это сделать в Pharo. Я сделал кучу googling для регулярного выражения Pharo, но ничего не понял. Является ли эта возможность частью класса RxMatcher или некоторого другого класса регулярных выражений Pharo?

+0

кажется Pharo не поддерживает замену с захватом группы – rock321987

+0

Ну, вы пробовали обычные стили ссылочности? Как '\ 1', или' \\ 1' или '$ 1' (возможно, с' matchesReplacedWith')? Группы захвата поддерживаются, это ясно из того, что может быть выполнено в Pharo, но нет никакого намека на то, поддерживаются ли обратные ссылки как части шаблонов замены. –

+1

@ WiktorStribiżew Да, я пробовал '\ 1',' \\ 1' и '$ 1'. В каждом случае заменой была буквальная строка. Я обновил свой вопрос, указав эти попытки. Я вижу, что группы захвата поддерживаются, насколько подходит. В документации есть примеры для захвата и перечисления захватов. Тем не менее, ничего о обратном обращении с ними в заменяющей строке. Это кажется фундаментальным для поиска/замены регулярных выражений, поэтому я удивлен, что он не поддерживается. – lurker

ответ

1

После экспериментов немного с RxMatcher класса, я сделал следующее изменение в RxMatcher#copyStream:to:replacingMatchesWith: селектор:

copyStream: aStream to: writeStream replacingMatchesWith: aString 
    "Copy the contents of <aStream> on the <writeStream>, 
    except for the matches. Replace each match with <aString>." 

    | searchStart matchStart matchEnd | 
    stream := aStream. 
    markerPositions := nil. 
    [searchStart := aStream position. 
    self proceedSearchingStream: aStream] whileTrue: [ | ws rep | 
     matchStart := (self subBeginning: 1) first. 
     matchEnd := (self subEnd: 1) first. 
     aStream position: searchStart. 
     searchStart to: matchStart - 1 do: 
      [:ignoredPos | writeStream nextPut: aStream next]. 

     "------- The following lines replaced: writeStream nextPutAll: aString ------" 
     "Do the regex replacement including lookback substitutions" 
     writeStream nextPutAll: (aString format: self subexpressionStrings). 
     "-------" 

     aStream position: matchEnd. 
     "Be extra careful about successful matches which consume no input. 
     After those, make sure to advance or finish if already at end." 
     matchEnd = searchStart ifTrue: 
      [aStream atEnd 
       ifTrue: [^self "rest after end of whileTrue: block is a no-op if atEnd"] 
       ifFalse: [writeStream nextPut: aStream next]]]. 
    aStream position: searchStart. 
    [aStream atEnd] whileFalse: [writeStream nextPut: aStream next] 

А потом «доступ» Категория:

subexpressionStrings 
    "Create an array of lookback strings" 
    | ws | 
    ws := Array new writeStream. 
    2 to: (self subexpressionCount) do: [ :n | | se | 
     ws nextPut: ((se := self subexpression: n) ifNil: [ '' ] ifNotNil: [ se ]) ]. 
    ^ws contents. 

С этой модификацией я могу сделать обратную замену в строке замены, используя шаблон Smalltalk String#format: для аргументов:

re := '((foo|re)ba(r|m))' asRegex 
re copy: 'foobar meh rebam' replacingMatchesWith: '{2}bu{3} (was {1})' 

Результаты в:

'foobur (was foobar) meh rebum (was rebam)' 
0

Вы проверили Regex help? Там нет #replacingAllRegex:, но сличитель имеет #subexpression:

+0

Разве это не комментарий? ;) Я прочитал всю онлайн-документацию по регулярному выражению Фраро, которую я смог найти (это почти все повторяющиеся экземпляры). Я знаю, что в Pharo нет '#replacingAllRegex:'.Я цитировал это как пример того, что я мог бы сделать в GNU Smalltalk. Я знаю, что у matcher есть '#subexpression:', но нет селектора для выполнения замены регулярных выражений, которая имеет ссылки на те подвыражения, которые совпадают и как они существуют в библиотеках регулярных выражений других языков (включая GNU Smalltalk). Если я ошибаюсь, вы можете показать мне пример? – lurker