summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--re.c2
-rw-r--r--string.c40
-rw-r--r--test/ruby/test_string.rb2
3 files changed, 29 insertions, 15 deletions
diff --git a/re.c b/re.c
index 5927e9e9f3..70194be87e 100644
--- a/re.c
+++ b/re.c
@@ -3402,7 +3402,7 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
switch (c) {
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- if (onig_noname_group_capture_is_active(RREGEXP(regexp)->ptr)) {
+ if (!NIL_P(regexp) && onig_noname_group_capture_is_active(RREGEXP(regexp)->ptr)) {
no = c - '0';
}
else {
diff --git a/string.c b/string.c
index 2b0c69c6fc..8b5c1f6530 100644
--- a/string.c
+++ b/string.c
@@ -3957,17 +3957,16 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
char *p, *rp;
long len, rlen;
+ match = rb_backref_get();
+ regs = RMATCH_REGS(match);
if (RB_TYPE_P(pat, T_STRING)) {
beg0 = beg;
end0 = beg0 + RSTRING_LEN(pat);
match0 = pat;
}
else {
- match = rb_backref_get();
- regs = RMATCH_REGS(match);
beg0 = BEG(0);
end0 = END(0);
- if (!iter && NIL_P(hash)) repl = rb_reg_regsub(repl, str, regs, pat);
if (iter) match0 = rb_reg_nth_match(0, match);
}
@@ -3984,6 +3983,9 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
str_mod_check(str, p, len);
rb_check_frozen(str);
}
+ else {
+ repl = rb_reg_regsub(repl, str, regs, RB_TYPE_P(pat, T_STRING) ? Qnil : pat);
+ }
enc = rb_enc_compatible(str, repl);
if (!enc) {
@@ -4086,16 +4088,16 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
long beg, n;
long beg0, end0;
long offset, blen, slen, len, last;
- int iter = 0;
+ enum {STR, ITER, MAP} mode = STR;
char *sp, *cp;
int tainted = 0;
- int need_backref;
+ int need_backref = -1;
rb_encoding *str_enc;
switch (argc) {
case 1:
RETURN_ENUMERATOR(str, argc, argv);
- iter = 1;
+ mode = ITER;
break;
case 2:
repl = argv[1];
@@ -4103,6 +4105,9 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
if (NIL_P(hash)) {
StringValue(repl);
}
+ else {
+ mode = MAP;
+ }
if (OBJ_TAINTED(repl)) tainted = 1;
break;
default:
@@ -4110,7 +4115,6 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
}
pat = get_pat_quoted(argv[0], 1);
- need_backref = iter || !NIL_P(hash);
beg = rb_pat_search(pat, str, 0, need_backref);
if (beg < 0) {
if (bang) return Qnil; /* no match, no substitution */
@@ -4131,23 +4135,21 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
do {
n++;
+ match = rb_backref_get();
+ regs = RMATCH_REGS(match);
if (RB_TYPE_P(pat, T_STRING)) {
beg0 = beg;
end0 = beg0 + RSTRING_LEN(pat);
- if (!need_backref) val = repl;
match0 = pat;
}
else {
- match = rb_backref_get();
- regs = RMATCH_REGS(match);
beg0 = BEG(0);
end0 = END(0);
- if (!need_backref) val = rb_reg_regsub(repl, str, regs, pat);
- if (iter) match0 = rb_reg_nth_match(0, match);
+ if (mode == ITER) match0 = rb_reg_nth_match(0, match);
}
- if (need_backref) {
- if (iter) {
+ if (mode) {
+ if (mode == ITER) {
val = rb_obj_as_string(rb_yield(match0));
}
else {
@@ -4159,6 +4161,16 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
rb_raise(rb_eRuntimeError, "block should not cheat");
}
}
+ else if (need_backref) {
+ val = rb_reg_regsub(repl, str, regs, RB_TYPE_P(pat, T_STRING) ? Qnil : pat);
+ if (need_backref < 0) {
+ need_backref = val != repl;
+ }
+ }
+ else {
+ val = repl;
+ }
+
if (OBJ_TAINTED(val)) tainted = 1;
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index 62402353a7..5ee026c327 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -808,6 +808,7 @@ class TestString < Test::Unit::TestCase
S("hello").gsub(/./) { |s| s[0].to_s + S(' ')})
assert_equal(S("HELL-o"),
S("hello").gsub(/(hell)(.)/) { |s| $1.upcase + S('-') + $2 })
+ assert_equal(S("<>h<>e<>l<>l<>o<>"), S("hello").gsub(S(''), S('<\0>')))
a = S("hello")
a.taint
@@ -1415,6 +1416,7 @@ class TestString < Test::Unit::TestCase
assert_equal(S("HELL-o"), S("hello").sub(/(hell)(.)/) {
|s| $1.upcase + S('-') + $2
})
+ assert_equal(S("h<e>llo"), S("hello").sub('e', S('<\0>')))
assert_equal(S("a\\aba"), S("ababa").sub(/b/, '\\'))
assert_equal(S("ab\\aba"), S("ababa").sub(/(b)/, '\1\\'))