2006/01/27

ううん、昨日の regexp-replace-delimiter-all* では後方参照が使えないな。gaucheのregexp.scmを見ると、regexp-replace-all が最後まで \1 などをサブマッチした文字列に置き換えないらしく、それが原因っぽい。例えば #/foo(.*?)bar/ という正規表現オブジェクトは、内部では ("for" 1 "bar") というリストになっていて、それが regexp-replace-rec という regexp-replace-系プロシージャの請負プロシージャで rxmatch-substring により展開される。昨日の状態で置き換える文字列 に \1 などが指定されていても、最初にデリミタで分解されてしまうので、最終的に取り出される文字列は "1" とかになっちゃう。
置換文字列としてはマッチオブジェクトを引数にしたプロシージャが渡せるので、デリミタを施す処理を外でやるようにすれば対処はできるんだけど……

(define delimiter "%%%")
(define (set-delimiter str)
(string-append
delimiter
(string-join (map x->string (string->list str)) delimiter)
delimiter))
(define (erace-delimiter str)
(regexp-replace-all (string->regexp delimiter) str ""))

(define (regexp-replace-delimiter-all* str . args)
(if (eq? (remainder (length args) 2) 1)
(error
"Need even args -- REGEXP-MATCH-REPLACE*"
args)
(if (null? args)
(erace-delimiter str)
(apply regexp-replace-delimiter-all*
(append
(list (regexp-replace-all
(car args)
str
(cadr args)))
(cddr args))))))

(regexp-replace-delimiter-all* "foobarbaz..."
#/foo(.*?)baz/
(lambda (m) (set-delimiter
(string-append
"|"
(rxmatch-substring m 1)
"|"
)))
#/bar/
(lambda (m) (set-delimiter "..."))
)
 
=> "|bar|..."

なんかだんだん意図がわからなくなってきたけど、ようは regexp-replace-all* だとこうなっちゃうのをなんとかしたいということです。

(regexp-replace-all* "foobarbaz..."
#/foo(.*?)baz/
(lambda (m) (string-append
"|"
(rxmatch-substring m 1)
"|"
))
#/bar/
(lambda (m) "...")
)

=> "|...|..."

No comments :