зеркало из https://github.com/github/ruby.git
string.c: backref substitution
* re.c (rb_reg_regsub): allow nil regexp for string matching. * string.c (rb_str_sub_bang, str_gsub): make substitution if replacement string has backref escapes. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45459 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
2d82342cf2
Коммит
2f14bde88f
2
re.c
2
re.c
|
@ -3402,7 +3402,7 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '1': case '2': case '3': case '4':
|
case '1': case '2': case '3': case '4':
|
||||||
case '5': case '6': case '7': case '8': case '9':
|
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';
|
no = c - '0';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
40
string.c
40
string.c
|
@ -3957,17 +3957,16 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
|
||||||
char *p, *rp;
|
char *p, *rp;
|
||||||
long len, rlen;
|
long len, rlen;
|
||||||
|
|
||||||
|
match = rb_backref_get();
|
||||||
|
regs = RMATCH_REGS(match);
|
||||||
if (RB_TYPE_P(pat, T_STRING)) {
|
if (RB_TYPE_P(pat, T_STRING)) {
|
||||||
beg0 = beg;
|
beg0 = beg;
|
||||||
end0 = beg0 + RSTRING_LEN(pat);
|
end0 = beg0 + RSTRING_LEN(pat);
|
||||||
match0 = pat;
|
match0 = pat;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
match = rb_backref_get();
|
|
||||||
regs = RMATCH_REGS(match);
|
|
||||||
beg0 = BEG(0);
|
beg0 = BEG(0);
|
||||||
end0 = END(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);
|
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);
|
str_mod_check(str, p, len);
|
||||||
rb_check_frozen(str);
|
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);
|
enc = rb_enc_compatible(str, repl);
|
||||||
if (!enc) {
|
if (!enc) {
|
||||||
|
@ -4086,16 +4088,16 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
|
||||||
long beg, n;
|
long beg, n;
|
||||||
long beg0, end0;
|
long beg0, end0;
|
||||||
long offset, blen, slen, len, last;
|
long offset, blen, slen, len, last;
|
||||||
int iter = 0;
|
enum {STR, ITER, MAP} mode = STR;
|
||||||
char *sp, *cp;
|
char *sp, *cp;
|
||||||
int tainted = 0;
|
int tainted = 0;
|
||||||
int need_backref;
|
int need_backref = -1;
|
||||||
rb_encoding *str_enc;
|
rb_encoding *str_enc;
|
||||||
|
|
||||||
switch (argc) {
|
switch (argc) {
|
||||||
case 1:
|
case 1:
|
||||||
RETURN_ENUMERATOR(str, argc, argv);
|
RETURN_ENUMERATOR(str, argc, argv);
|
||||||
iter = 1;
|
mode = ITER;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
repl = argv[1];
|
repl = argv[1];
|
||||||
|
@ -4103,6 +4105,9 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
|
||||||
if (NIL_P(hash)) {
|
if (NIL_P(hash)) {
|
||||||
StringValue(repl);
|
StringValue(repl);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
mode = MAP;
|
||||||
|
}
|
||||||
if (OBJ_TAINTED(repl)) tainted = 1;
|
if (OBJ_TAINTED(repl)) tainted = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -4110,7 +4115,6 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
|
||||||
}
|
}
|
||||||
|
|
||||||
pat = get_pat_quoted(argv[0], 1);
|
pat = get_pat_quoted(argv[0], 1);
|
||||||
need_backref = iter || !NIL_P(hash);
|
|
||||||
beg = rb_pat_search(pat, str, 0, need_backref);
|
beg = rb_pat_search(pat, str, 0, need_backref);
|
||||||
if (beg < 0) {
|
if (beg < 0) {
|
||||||
if (bang) return Qnil; /* no match, no substitution */
|
if (bang) return Qnil; /* no match, no substitution */
|
||||||
|
@ -4131,23 +4135,21 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
|
||||||
do {
|
do {
|
||||||
n++;
|
n++;
|
||||||
|
|
||||||
|
match = rb_backref_get();
|
||||||
|
regs = RMATCH_REGS(match);
|
||||||
if (RB_TYPE_P(pat, T_STRING)) {
|
if (RB_TYPE_P(pat, T_STRING)) {
|
||||||
beg0 = beg;
|
beg0 = beg;
|
||||||
end0 = beg0 + RSTRING_LEN(pat);
|
end0 = beg0 + RSTRING_LEN(pat);
|
||||||
if (!need_backref) val = repl;
|
|
||||||
match0 = pat;
|
match0 = pat;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
match = rb_backref_get();
|
|
||||||
regs = RMATCH_REGS(match);
|
|
||||||
beg0 = BEG(0);
|
beg0 = BEG(0);
|
||||||
end0 = END(0);
|
end0 = END(0);
|
||||||
if (!need_backref) val = rb_reg_regsub(repl, str, regs, pat);
|
if (mode == ITER) match0 = rb_reg_nth_match(0, match);
|
||||||
if (iter) match0 = rb_reg_nth_match(0, match);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_backref) {
|
if (mode) {
|
||||||
if (iter) {
|
if (mode == ITER) {
|
||||||
val = rb_obj_as_string(rb_yield(match0));
|
val = rb_obj_as_string(rb_yield(match0));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -4159,6 +4161,16 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
|
||||||
rb_raise(rb_eRuntimeError, "block should not cheat");
|
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;
|
if (OBJ_TAINTED(val)) tainted = 1;
|
||||||
|
|
||||||
|
|
|
@ -808,6 +808,7 @@ class TestString < Test::Unit::TestCase
|
||||||
S("hello").gsub(/./) { |s| s[0].to_s + S(' ')})
|
S("hello").gsub(/./) { |s| s[0].to_s + S(' ')})
|
||||||
assert_equal(S("HELL-o"),
|
assert_equal(S("HELL-o"),
|
||||||
S("hello").gsub(/(hell)(.)/) { |s| $1.upcase + S('-') + $2 })
|
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 = S("hello")
|
||||||
a.taint
|
a.taint
|
||||||
|
@ -1415,6 +1416,7 @@ class TestString < Test::Unit::TestCase
|
||||||
assert_equal(S("HELL-o"), S("hello").sub(/(hell)(.)/) {
|
assert_equal(S("HELL-o"), S("hello").sub(/(hell)(.)/) {
|
||||||
|s| $1.upcase + S('-') + $2
|
|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("a\\aba"), S("ababa").sub(/b/, '\\'))
|
||||||
assert_equal(S("ab\\aba"), S("ababa").sub(/(b)/, '\1\\'))
|
assert_equal(S("ab\\aba"), S("ababa").sub(/(b)/, '\1\\'))
|
||||||
|
|
Загрузка…
Ссылка в новой задаче