行頭/^/のみでの置換は無限ループに注意

aaa
bbb

>aaa
>bbb

こういう処理を考える。

Rubyの場合

普通に/^/を">"に置換すればいい。

irb> "aaa\nbbb\n".gsub(/^/,">")
=> ">aaa\n>bbb\n"

Gaucheの場合

rubyと同様に#/^/を">"に置換しようとすると無限ループになってしまう。

gosh> (regexp-replace-all #/^/ "aaa\nbbb\n" ">")
 *** ERROR: regexp-replace-all: matching zero-length string causes infinite loop: #/^/

これは#/^/だけのマッチでは、マッチした部分の後ろの部分=もとの文字列、となってしまうため。

註: regexp-replace-all は文字列でマッチした部分の後ろの部分に ついて再帰的に自分自身を適用します。

http://practical-scheme.net/gauche/man/gauche-refj_49.html

なので、例えば以下のように次の行頭までマッチ部分をのばしてやれば回避出来る。

gosh> (regexp-replace-all #/.*?\n/ "aaa\nbbb\n" ">\\0")
">aaa\n>bbb\n"

Haskellの場合

もしやと思って試してみたら、Haskellでも無限ループになった。

Prelude> :m Text.Regex
Prelude Text.Regex> subRegex (mkRegex "^") "aaa\nbbb\n" ">"
"Interrupted.

なのでこれも同様に…おっと、Text.Regexには最小マッチ/.*?/がなかった。

Prelude Text.Regex> subRegex (mkRegex ".*?\n") "aaa\nbbb\n" ">\\0"
"*** Exception: Text.Regex.Posix.regcomp: error in pattern

これならOK。

Prelude Text.Regex> subRegex (mkRegex "[^\n]*\n") "aaa\nbbb\n" ">\\0"
">aaa\n>bbb\n"

JavaScriptの場合

無限ループにはならないけどちょっとだけ挙動が違う。

js> "aaa\nbbb\n".replace(/^/mg,">")
>aaa
>bbb
>

なのでこれも同様に…おっと、マッチ全体の参照は\0じゃなかった。

js> "aaa\nbbb\n".replace(/.*?\n/mg,">\\0")
>\0>\0

これならOK。

js> "aaa\nbbb\n".replace(/.*?\n/mg,">$&")
>aaa
>bbb