Commit 5c6de685 authored by Yukihiro "Matz" Matsumoto's avatar Yukihiro "Matz" Matsumoto

Merge pull request #2828 from iij/pr-string-sub-backslash

gsub/sub supports back references in substitutes.  fixes #2816.
parents a0411626 5dd2b8e1
......@@ -20,6 +20,30 @@ class String
self
end
# private method for gsub/sub
def __sub_replace(pre, m, post)
s = ""
i = 0
while j = index("\\", i)
break if j == length-1
t = case self[j+1]
when "\\"
"\\"
when "`"
pre
when "&", "0"
m
when "'"
post
else
self[j, 2]
end
s += self[i, j-i] + t
i = j + 2
end
s + self[i, length-i]
end
##
# Replace all matches of +pattern+ with +replacement+.
# Call block (if given) for each match and replace
......@@ -29,7 +53,17 @@ class String
# ISO 15.2.10.5.18
def gsub(*args, &block)
if args.size == 2
split(args[0], -1).join(args[1])
s = ""
i = 0
while j = index(args[0], i)
seplen = args[0].length
k = j + seplen
pre = self[0, j]
post = self[k, length-k]
s += self[i, j-i] + args[1].__sub_replace(pre, args[0], post)
i = k
end
s + self[i, length-i]
elsif args.size == 1 && block
split(args[0], -1).join(block.call(args[0]))
else
......@@ -76,7 +110,8 @@ class String
# ISO 15.2.10.5.36
def sub(*args, &block)
if args.size == 2
split(args[0], 2).join(args[1])
pre, post = split(args[0], 2)
pre + args[1].__sub_replace(pre, args[0], post) + post
elsif args.size == 1 && block
split(args[0], 2).join(block.call(args[0]))
else
......
......@@ -254,6 +254,15 @@ assert('String#gsub', '15.2.10.5.18') do
assert_equal('A', 'a'.gsub('a'){|w| w.capitalize })
end
assert('String#gsub with backslash') do
s = 'abXcdXef'
assert_equal 'ab<\\>cd<\\>ef', s.gsub('X', '<\\\\>')
assert_equal 'ab<X>cd<X>ef', s.gsub('X', '<\\&>')
assert_equal 'ab<X>cd<X>ef', s.gsub('X', '<\\0>')
assert_equal 'ab<ab>cd<abXcd>ef', s.gsub('X', '<\\`>')
assert_equal 'ab<cdXef>cd<ef>ef', s.gsub('X', '<\\\'>')
end
assert('String#gsub!', '15.2.10.5.19') do
a = 'abcabc'
a.gsub!('b', 'B')
......@@ -416,6 +425,15 @@ assert('String#sub', '15.2.10.5.36') do
assert_equal 'aa$', 'aa#'.sub('#', '$')
end
assert('String#sub with backslash') do
s = 'abXcdXef'
assert_equal 'ab<\\>cdXef', s.sub('X', '<\\\\>')
assert_equal 'ab<X>cdXef', s.sub('X', '<\\&>')
assert_equal 'ab<X>cdXef', s.sub('X', '<\\0>')
assert_equal 'ab<ab>cdXef', s.sub('X', '<\\`>')
assert_equal 'ab<cdXef>cdXef', s.sub('X', '<\\\'>')
end
assert('String#sub!', '15.2.10.5.37') do
a = 'abcabc'
a.sub!('b', 'B')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment