gsub, when replacing, offsets after each replacement by the length of the match, not the length of the replacement, which means that if the replacement contains something that will re-match after that limit, gsub will loop forever:
λ> gsub [re|bad|] "xxbad" "this is bad, right?" -- length "xx" < length "bad", so ok
"this is xxbad, right?"
λ> gsub [re|bad|] "xxxbad" "this is bad, right?" -- length "xxx" >= length "bad", so loop
"^CInterrupted.
Similarly, it can miss targets that occur soon after a shortening replacement:
gsub
, when replacing, offsets after each replacement by the length of the match, not the length of the replacement, which means that if the replacement contains something that will re-match after that limit, gsub will loop forever:Similarly, it can miss targets that occur soon after a shortening replacement:
The ultimate bug's in
rawSub
, where it returnsend
instead ofoffset + length replacement
.