Add String#bytesplice
This commit is contained in:
parent
b8e72bd2e9
commit
1107839a7f
Notes:
git
2022-03-18 11:51:26 +09:00
71
string.c
71
string.c
@ -6296,6 +6296,76 @@ rb_str_byteslice(int argc, VALUE *argv, VALUE str)
|
||||
return str_byte_aref(str, argv[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* bytesplice(index, length, str) -> string
|
||||
* bytesplice(range, str) -> string
|
||||
*
|
||||
* Replaces some or all of the content of +self+ with +str+, and returns +str+.
|
||||
* The portion of the string affected is determined using
|
||||
* the same criteria as String#byteslice, except that +length+ cannot be omitted.
|
||||
* If the replacement string is not the same length as the text it is replacing,
|
||||
* the string will be adjusted accordingly.
|
||||
* The form that take an Integer will raise an IndexError if the value is out
|
||||
* of range; the Range form will raise a RangeError.
|
||||
* If the beginning or ending offset does not land on character (codepoint)
|
||||
* boundary, an IndexError will be raised.
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_str_bytesplice(int argc, VALUE *argv, VALUE str)
|
||||
{
|
||||
long beg, end, len, slen;
|
||||
VALUE val;
|
||||
rb_encoding *enc;
|
||||
int cr;
|
||||
|
||||
rb_check_arity(argc, 2, 3);
|
||||
if (argc == 2) {
|
||||
if (!rb_range_beg_len(argv[0], &beg, &len, RSTRING_LEN(str), 2)) {
|
||||
rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
|
||||
rb_builtin_class_name(argv[0]));
|
||||
}
|
||||
val = argv[1];
|
||||
}
|
||||
else {
|
||||
beg = NUM2LONG(argv[0]);
|
||||
len = NUM2LONG(argv[1]);
|
||||
val = argv[2];
|
||||
}
|
||||
if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len);
|
||||
slen = RSTRING_LEN(str);
|
||||
if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
|
||||
rb_raise(rb_eIndexError, "index %ld out of string", beg);
|
||||
}
|
||||
if (beg < 0) {
|
||||
beg += slen;
|
||||
}
|
||||
assert(beg >= 0);
|
||||
assert(beg <= slen);
|
||||
if (len > slen - beg) {
|
||||
len = slen - beg;
|
||||
}
|
||||
end = beg + len;
|
||||
if (!str_check_byte_pos(str, beg)) {
|
||||
rb_raise(rb_eIndexError,
|
||||
"offset %ld does not land on character boundary", beg);
|
||||
}
|
||||
if (!str_check_byte_pos(str, end)) {
|
||||
rb_raise(rb_eIndexError,
|
||||
"offset %ld does not land on character boundary", end);
|
||||
}
|
||||
StringValue(val);
|
||||
enc = rb_enc_check(str, val);
|
||||
str_modify_keep_cr(str);
|
||||
rb_str_splice_0(str, beg, len, val);
|
||||
rb_enc_associate(str, enc);
|
||||
cr = ENC_CODERANGE_AND(ENC_CODERANGE(str), ENC_CODERANGE(val));
|
||||
if (cr != ENC_CODERANGE_BROKEN)
|
||||
ENC_CODERANGE_SET(str, cr);
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* reverse -> string
|
||||
@ -12560,6 +12630,7 @@ Init_String(void)
|
||||
rb_define_method(rb_cString, "getbyte", rb_str_getbyte, 1);
|
||||
rb_define_method(rb_cString, "setbyte", rb_str_setbyte, 2);
|
||||
rb_define_method(rb_cString, "byteslice", rb_str_byteslice, -1);
|
||||
rb_define_method(rb_cString, "bytesplice", rb_str_bytesplice, -1);
|
||||
rb_define_method(rb_cString, "scrub", str_scrub, -1);
|
||||
rb_define_method(rb_cString, "scrub!", str_scrub_bang, -1);
|
||||
rb_define_method(rb_cString, "freeze", rb_str_freeze, 0);
|
||||
|
@ -3395,6 +3395,50 @@ CODE
|
||||
assert_nil(S("こ").byterindex(S("こんにちは")))
|
||||
assert_nil(S("").byterindex(S("こんにちは")))
|
||||
end
|
||||
|
||||
def test_bytesplice
|
||||
assert_bytesplice_raise(IndexError, S("hello"), -6, 0, "xxx")
|
||||
assert_bytesplice_result("xxxhello", S("hello"), -5, 0, "xxx")
|
||||
assert_bytesplice_result("xxxhello", S("hello"), 0, 0, "xxx")
|
||||
assert_bytesplice_result("xxxello", S("hello"), 0, 1, "xxx")
|
||||
assert_bytesplice_result("xxx", S("hello"), 0, 5, "xxx")
|
||||
assert_bytesplice_result("xxx", S("hello"), 0, 6, "xxx")
|
||||
|
||||
assert_bytesplice_raise(RangeError, S("hello"), -6...-6, "xxx")
|
||||
assert_bytesplice_result("xxxhello", S("hello"), -5...-5, "xxx")
|
||||
assert_bytesplice_result("xxxhello", S("hello"), 0...0, "xxx")
|
||||
assert_bytesplice_result("xxxello", S("hello"), 0..0, "xxx")
|
||||
assert_bytesplice_result("xxxello", S("hello"), 0...1, "xxx")
|
||||
assert_bytesplice_result("xxxllo", S("hello"), 0..1, "xxx")
|
||||
assert_bytesplice_result("xxx", S("hello"), 0..-1, "xxx")
|
||||
assert_bytesplice_result("xxx", S("hello"), 0...5, "xxx")
|
||||
assert_bytesplice_result("xxx", S("hello"), 0...6, "xxx")
|
||||
|
||||
assert_bytesplice_raise(TypeError, S("hello"), 0, "xxx")
|
||||
|
||||
assert_bytesplice_raise(IndexError, S("こんにちは"), -16, 0, "xxx")
|
||||
assert_bytesplice_result("xxxこんにちは", S("こんにちは"), -15, 0, "xxx")
|
||||
assert_bytesplice_result("xxxこんにちは", S("こんにちは"), 0, 0, "xxx")
|
||||
assert_bytesplice_raise(IndexError, S("こんにちは"), 1, 0, "xxx")
|
||||
assert_bytesplice_raise(IndexError, S("こんにちは"), 0, 1, "xxx")
|
||||
assert_bytesplice_raise(IndexError, S("こんにちは"), 0, 2, "xxx")
|
||||
assert_bytesplice_result("xxxんにちは", S("こんにちは"), 0, 3, "xxx")
|
||||
assert_bytesplice_result("こんにちはxxx", S("こんにちは"), 15, 0, "xxx")
|
||||
|
||||
assert_bytesplice_result("", S(""), 0, 0, "")
|
||||
assert_bytesplice_result("xxx", S(""), 0, 0, "xxx")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assert_bytesplice_result(expected, s, *args)
|
||||
assert_equal(args.last, s.send(:bytesplice, *args))
|
||||
assert_equal(expected, s)
|
||||
end
|
||||
|
||||
def assert_bytesplice_raise(e, s, *args)
|
||||
assert_raise(e) { s.send(:bytesplice, *args) }
|
||||
end
|
||||
end
|
||||
|
||||
class TestString2 < TestString
|
||||
|
Loading…
x
Reference in New Issue
Block a user