mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Add String#byteindex, String#byterindex, and MatchData#byteoffset (#5518)
* Add String#byteindex, String#byterindex, and MatchData#byteoffset [Feature #13110] Co-authored-by: NARUSE, Yui <naruse@airemix.jp>
This commit is contained in:
parent
db6b23c76c
commit
c8817d6a3e
Notes:
git
2022-02-19 19:10:20 +09:00
Merged-By: shugo <shugo@ruby-lang.org>
5 changed files with 451 additions and 9 deletions
6
NEWS.md
6
NEWS.md
|
@ -59,6 +59,9 @@ Note: We're only listing outstanding class updates.
|
|||
empty, instead of returning the default value or
|
||||
calling the default proc. [[Bug #16908]]
|
||||
|
||||
* MatchData
|
||||
* MatchData#byteoffset has been added. [[Feature #13110]]
|
||||
|
||||
* Module
|
||||
* Module.used_refinements has been added. [[Feature #14332]]
|
||||
* Module#refinements has been added. [[Feature #12737]]
|
||||
|
@ -74,6 +77,9 @@ Note: We're only listing outstanding class updates.
|
|||
* Set is now available as a builtin class without the need for `require "set"`. [[Feature #16989]]
|
||||
It is currently autoloaded via the `Set` constant or a call to `Enumerable#to_set`.
|
||||
|
||||
* String
|
||||
* String#byteindex and String#byterindex have been added. [[Feature #13110]]
|
||||
|
||||
* Struct
|
||||
* A Struct class can also be initialized with keyword arguments
|
||||
without `keyword_init: true` on `Struct.new` [[Feature #16806]]
|
||||
|
|
33
re.c
33
re.c
|
@ -1234,6 +1234,38 @@ match_offset(VALUE match, VALUE n)
|
|||
LONG2NUM(RMATCH(match)->rmatch->char_offset[i].end));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* mtch.byteoffset(n) -> array
|
||||
*
|
||||
* Returns a two-element array containing the beginning and ending byte-based offsets of
|
||||
* the <em>n</em>th match.
|
||||
* <em>n</em> can be a string or symbol to reference a named capture.
|
||||
*
|
||||
* m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
||||
* m.byteoffset(0) #=> [1, 7]
|
||||
* m.byteoffset(4) #=> [6, 7]
|
||||
*
|
||||
* m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
|
||||
* p m.byteoffset(:foo) #=> [0, 1]
|
||||
* p m.byteoffset(:bar) #=> [2, 3]
|
||||
*
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
match_byteoffset(VALUE match, VALUE n)
|
||||
{
|
||||
int i = match_backref_number(match, n);
|
||||
struct re_registers *regs = RMATCH_REGS(match);
|
||||
|
||||
match_check(match);
|
||||
backref_number_check(regs, i);
|
||||
|
||||
if (BEG(i) < 0)
|
||||
return rb_assoc_new(Qnil, Qnil);
|
||||
return rb_assoc_new(LONG2NUM(BEG(i)), LONG2NUM(END(i)));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
|
@ -4162,6 +4194,7 @@ Init_Regexp(void)
|
|||
rb_define_method(rb_cMatch, "size", match_size, 0);
|
||||
rb_define_method(rb_cMatch, "length", match_size, 0);
|
||||
rb_define_method(rb_cMatch, "offset", match_offset, 1);
|
||||
rb_define_method(rb_cMatch, "byteoffset", match_byteoffset, 1);
|
||||
rb_define_method(rb_cMatch, "begin", match_begin, 1);
|
||||
rb_define_method(rb_cMatch, "end", match_end, 1);
|
||||
rb_define_method(rb_cMatch, "match", match_nth, 1);
|
||||
|
|
260
string.c
260
string.c
|
@ -3979,18 +3979,123 @@ rb_str_index_m(int argc, VALUE *argv, VALUE str)
|
|||
return LONG2NUM(pos);
|
||||
}
|
||||
|
||||
/* whether given pos is valid character boundary or not
|
||||
* Note that in this function, "character" means a code point
|
||||
* (Unicode scalar value), not a grapheme cluster.
|
||||
*/
|
||||
static bool
|
||||
str_check_byte_pos(VALUE str, long pos)
|
||||
{
|
||||
const char *s = RSTRING_PTR(str);
|
||||
const char *e = RSTRING_END(str);
|
||||
const char *p = s + pos;
|
||||
const char *pp = rb_enc_left_char_head(s, p, e, rb_enc_get(str));
|
||||
return p == pp;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* byteindex(substring, offset = 0) -> integer or nil
|
||||
* byteindex(regexp, offset = 0) -> integer or nil
|
||||
*
|
||||
* Returns the \Integer byte-based index of the first occurrence of the given +substring+,
|
||||
* or +nil+ if none found:
|
||||
*
|
||||
* 'foo'.byteindex('f') # => 0
|
||||
* 'foo'.byteindex('o') # => 1
|
||||
* 'foo'.byteindex('oo') # => 1
|
||||
* 'foo'.byteindex('ooo') # => nil
|
||||
*
|
||||
* Returns the \Integer byte-based index of the first match for the given \Regexp +regexp+,
|
||||
* or +nil+ if none found:
|
||||
*
|
||||
* 'foo'.byteindex(/f/) # => 0
|
||||
* 'foo'.byteindex(/o/) # => 1
|
||||
* 'foo'.byteindex(/oo/) # => 1
|
||||
* 'foo'.byteindex(/ooo/) # => nil
|
||||
*
|
||||
* \Integer argument +offset+, if given, specifies the byte-based position in the
|
||||
* string to begin the search:
|
||||
*
|
||||
* 'foo'.byteindex('o', 1) # => 1
|
||||
* 'foo'.byteindex('o', 2) # => 2
|
||||
* 'foo'.byteindex('o', 3) # => nil
|
||||
*
|
||||
* If +offset+ is negative, counts backward from the end of +self+:
|
||||
*
|
||||
* 'foo'.byteindex('o', -1) # => 2
|
||||
* 'foo'.byteindex('o', -2) # => 1
|
||||
* 'foo'.byteindex('o', -3) # => 1
|
||||
* 'foo'.byteindex('o', -4) # => nil
|
||||
*
|
||||
* If +offset+ does not land on character (codepoint) boundary, +IndexError+ is
|
||||
* raised.
|
||||
*
|
||||
* Related: String#index, String#byterindex.
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_str_byteindex_m(int argc, VALUE *argv, VALUE str)
|
||||
{
|
||||
VALUE sub;
|
||||
VALUE initpos;
|
||||
long pos;
|
||||
|
||||
if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
|
||||
pos = NUM2LONG(initpos);
|
||||
}
|
||||
else {
|
||||
pos = 0;
|
||||
}
|
||||
if (pos < 0) {
|
||||
pos += RSTRING_LEN(str);
|
||||
if (pos < 0) {
|
||||
if (RB_TYPE_P(sub, T_REGEXP)) {
|
||||
rb_backref_set(Qnil);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
if (!str_check_byte_pos(str, pos)) {
|
||||
rb_raise(rb_eIndexError,
|
||||
"offset %ld does not land on character boundary", pos);
|
||||
}
|
||||
|
||||
if (RB_TYPE_P(sub, T_REGEXP)) {
|
||||
if (pos > RSTRING_LEN(str))
|
||||
return Qnil;
|
||||
if (rb_reg_search(sub, str, pos, 0) < 0) {
|
||||
return Qnil;
|
||||
}
|
||||
else {
|
||||
VALUE match = rb_backref_get();
|
||||
struct re_registers *regs = RMATCH_REGS(match);
|
||||
pos = BEG(0);
|
||||
return LONG2NUM(pos);
|
||||
}
|
||||
}
|
||||
else {
|
||||
StringValue(sub);
|
||||
pos = rb_strseq_index(str, sub, pos, 1);
|
||||
}
|
||||
|
||||
if (pos == -1) return Qnil;
|
||||
return LONG2NUM(pos);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MEMRCHR
|
||||
static long
|
||||
str_rindex(VALUE str, VALUE sub, const char *s, long pos, rb_encoding *enc)
|
||||
str_rindex(VALUE str, VALUE sub, const char *s, rb_encoding *enc)
|
||||
{
|
||||
char *hit, *adjusted;
|
||||
int c;
|
||||
long slen, searchlen;
|
||||
char *sbeg, *e, *t;
|
||||
|
||||
slen = RSTRING_LEN(sub);
|
||||
if (slen == 0) return pos;
|
||||
sbeg = RSTRING_PTR(str);
|
||||
slen = RSTRING_LEN(sub);
|
||||
if (slen == 0) return s - sbeg;
|
||||
e = RSTRING_END(str);
|
||||
t = RSTRING_PTR(sub);
|
||||
c = *t & 0xff;
|
||||
|
@ -4005,7 +4110,7 @@ str_rindex(VALUE str, VALUE sub, const char *s, long pos, rb_encoding *enc)
|
|||
continue;
|
||||
}
|
||||
if (memcmp(hit, t, slen) == 0)
|
||||
return rb_str_sublen(str, hit - sbeg);
|
||||
return hit - sbeg;
|
||||
searchlen = adjusted - sbeg;
|
||||
} while (searchlen > 0);
|
||||
|
||||
|
@ -4013,7 +4118,7 @@ str_rindex(VALUE str, VALUE sub, const char *s, long pos, rb_encoding *enc)
|
|||
}
|
||||
#else
|
||||
static long
|
||||
str_rindex(VALUE str, VALUE sub, const char *s, long pos, rb_encoding *enc)
|
||||
str_rindex(VALUE str, VALUE sub, const char *s, rb_encoding *enc)
|
||||
{
|
||||
long slen;
|
||||
char *sbeg, *e, *t;
|
||||
|
@ -4025,10 +4130,9 @@ str_rindex(VALUE str, VALUE sub, const char *s, long pos, rb_encoding *enc)
|
|||
|
||||
while (s) {
|
||||
if (memcmp(s, t, slen) == 0) {
|
||||
return pos;
|
||||
return s - sbeg;
|
||||
}
|
||||
if (pos == 0) break;
|
||||
pos--;
|
||||
if (s <= sbeg) break;
|
||||
s = rb_enc_prev_char(sbeg, s, e, enc);
|
||||
}
|
||||
|
||||
|
@ -4065,7 +4169,7 @@ rb_str_rindex(VALUE str, VALUE sub, long pos)
|
|||
}
|
||||
|
||||
s = str_nth(sbeg, RSTRING_END(str), pos, enc, singlebyte);
|
||||
return str_rindex(str, sub, s, pos, enc);
|
||||
return rb_str_sublen(str, str_rindex(str, sub, s, enc));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4170,6 +4274,142 @@ rb_str_rindex_m(int argc, VALUE *argv, VALUE str)
|
|||
return Qnil;
|
||||
}
|
||||
|
||||
static long
|
||||
rb_str_byterindex(VALUE str, VALUE sub, long pos)
|
||||
{
|
||||
long len, slen;
|
||||
char *sbeg, *s;
|
||||
rb_encoding *enc;
|
||||
|
||||
enc = rb_enc_check(str, sub);
|
||||
if (is_broken_string(sub)) return -1;
|
||||
len = RSTRING_LEN(str);
|
||||
slen = RSTRING_LEN(sub);
|
||||
|
||||
/* substring longer than string */
|
||||
if (len < slen) return -1;
|
||||
if (len - pos < slen) pos = len - slen;
|
||||
if (len == 0) return pos;
|
||||
|
||||
sbeg = RSTRING_PTR(str);
|
||||
|
||||
if (pos == 0) {
|
||||
if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = sbeg + pos;
|
||||
return str_rindex(str, sub, s, enc);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* byterindex(substring, offset = self.length) -> integer or nil
|
||||
* byterindex(regexp, offset = self.length) -> integer or nil
|
||||
*
|
||||
* Returns the \Integer byte-based index of the _last_ occurrence of the given +substring+,
|
||||
* or +nil+ if none found:
|
||||
*
|
||||
* 'foo'.byterindex('f') # => 0
|
||||
* 'foo'.byterindex('o') # => 2
|
||||
* 'foo'.byterindex('oo') # => 1
|
||||
* 'foo'.byterindex('ooo') # => nil
|
||||
*
|
||||
* Returns the \Integer byte-based index of the _last_ match for the given \Regexp +regexp+,
|
||||
* or +nil+ if none found:
|
||||
*
|
||||
* 'foo'.byterindex(/f/) # => 0
|
||||
* 'foo'.byterindex(/o/) # => 2
|
||||
* 'foo'.byterindex(/oo/) # => 1
|
||||
* 'foo'.byterindex(/ooo/) # => nil
|
||||
*
|
||||
* The _last_ match means starting at the possible last position, not
|
||||
* the last of longest matches.
|
||||
*
|
||||
* 'foo'.byterindex(/o+/) # => 2
|
||||
* $~ #=> #<MatchData "o">
|
||||
*
|
||||
* To get the last longest match, needs to combine with negative
|
||||
* lookbehind.
|
||||
*
|
||||
* 'foo'.byterindex(/(?<!o)o+/) # => 1
|
||||
* $~ #=> #<MatchData "oo">
|
||||
*
|
||||
* Or String#byteindex with negative lookforward.
|
||||
*
|
||||
* 'foo'.byteindex(/o+(?!.*o)/) # => 1
|
||||
* $~ #=> #<MatchData "oo">
|
||||
*
|
||||
* \Integer argument +offset+, if given and non-negative, specifies the maximum starting byte-based position in the
|
||||
* string to _end_ the search:
|
||||
*
|
||||
* 'foo'.byterindex('o', 0) # => nil
|
||||
* 'foo'.byterindex('o', 1) # => 1
|
||||
* 'foo'.byterindex('o', 2) # => 2
|
||||
* 'foo'.byterindex('o', 3) # => 2
|
||||
*
|
||||
* If +offset+ is a negative \Integer, the maximum starting position in the
|
||||
* string to _end_ the search is the sum of the string's length and +offset+:
|
||||
*
|
||||
* 'foo'.byterindex('o', -1) # => 2
|
||||
* 'foo'.byterindex('o', -2) # => 1
|
||||
* 'foo'.byterindex('o', -3) # => nil
|
||||
* 'foo'.byterindex('o', -4) # => nil
|
||||
*
|
||||
* If +offset+ does not land on character (codepoint) boundary, +IndexError+ is
|
||||
* raised.
|
||||
*
|
||||
* Related: String#byteindex.
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_str_byterindex_m(int argc, VALUE *argv, VALUE str)
|
||||
{
|
||||
VALUE sub;
|
||||
VALUE vpos;
|
||||
long pos, len = RSTRING_LEN(str);
|
||||
|
||||
if (rb_scan_args(argc, argv, "11", &sub, &vpos) == 2) {
|
||||
pos = NUM2LONG(vpos);
|
||||
if (pos < 0) {
|
||||
pos += len;
|
||||
if (pos < 0) {
|
||||
if (RB_TYPE_P(sub, T_REGEXP)) {
|
||||
rb_backref_set(Qnil);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
}
|
||||
if (pos > len) pos = len;
|
||||
}
|
||||
else {
|
||||
pos = len;
|
||||
}
|
||||
|
||||
if (!str_check_byte_pos(str, pos)) {
|
||||
rb_raise(rb_eIndexError,
|
||||
"offset %ld does not land on character boundary", pos);
|
||||
}
|
||||
|
||||
if (RB_TYPE_P(sub, T_REGEXP)) {
|
||||
if (rb_reg_search(sub, str, pos, 1) >= 0) {
|
||||
VALUE match = rb_backref_get();
|
||||
struct re_registers *regs = RMATCH_REGS(match);
|
||||
pos = BEG(0);
|
||||
return LONG2NUM(pos);
|
||||
}
|
||||
}
|
||||
else {
|
||||
StringValue(sub);
|
||||
pos = rb_str_byterindex(str, sub, pos);
|
||||
if (pos >= 0) return LONG2NUM(pos);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* string =~ regexp -> integer or nil
|
||||
|
@ -12382,7 +12622,9 @@ Init_String(void)
|
|||
rb_define_method(rb_cString, "next!", rb_str_succ_bang, 0);
|
||||
rb_define_method(rb_cString, "upto", rb_str_upto, -1);
|
||||
rb_define_method(rb_cString, "index", rb_str_index_m, -1);
|
||||
rb_define_method(rb_cString, "byteindex", rb_str_byteindex_m, -1);
|
||||
rb_define_method(rb_cString, "rindex", rb_str_rindex_m, -1);
|
||||
rb_define_method(rb_cString, "byterindex", rb_str_byterindex_m, -1);
|
||||
rb_define_method(rb_cString, "replace", rb_str_replace, 1);
|
||||
rb_define_method(rb_cString, "clear", rb_str_clear, 0);
|
||||
rb_define_method(rb_cString, "chr", rb_str_chr, 0);
|
||||
|
|
|
@ -424,6 +424,27 @@ class TestRegexp < Test::Unit::TestCase
|
|||
assert_equal([2, 3], m.offset(3))
|
||||
end
|
||||
|
||||
def test_match_byteoffset_begin_end
|
||||
m = /(?<x>b..)/.match("foobarbaz")
|
||||
assert_equal([3, 6], m.byteoffset("x"))
|
||||
assert_equal(3, m.begin("x"))
|
||||
assert_equal(6, m.end("x"))
|
||||
assert_raise(IndexError) { m.byteoffset("y") }
|
||||
assert_raise(IndexError) { m.byteoffset(2) }
|
||||
assert_raise(IndexError) { m.begin(2) }
|
||||
assert_raise(IndexError) { m.end(2) }
|
||||
|
||||
m = /(?<x>q..)?/.match("foobarbaz")
|
||||
assert_equal([nil, nil], m.byteoffset("x"))
|
||||
assert_equal(nil, m.begin("x"))
|
||||
assert_equal(nil, m.end("x"))
|
||||
|
||||
m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
|
||||
assert_equal([3, 6], m.byteoffset(1))
|
||||
assert_equal([nil, nil], m.byteoffset(2))
|
||||
assert_equal([6, 9], m.byteoffset(3))
|
||||
end
|
||||
|
||||
def test_match_to_s
|
||||
m = /(?<x>b..)/.match("foobarbaz")
|
||||
assert_equal("bar", m.to_s)
|
||||
|
|
|
@ -1340,6 +1340,15 @@ CODE
|
|||
assert_nil($~)
|
||||
|
||||
assert_equal(2, S("abcdbce").index(/b\Kc/))
|
||||
|
||||
assert_equal(0, S("こんにちは").index(?こ))
|
||||
assert_equal(1, S("こんにちは").index(S("んにち")))
|
||||
assert_equal(2, S("こんにちは").index(/にち./))
|
||||
|
||||
assert_equal(0, S("にんにちは").index(?に, 0))
|
||||
assert_equal(2, S("にんにちは").index(?に, 1))
|
||||
assert_equal(2, S("にんにちは").index(?に, 2))
|
||||
assert_nil(S("にんにちは").index(?に, 3))
|
||||
end
|
||||
|
||||
def test_insert
|
||||
|
@ -1502,6 +1511,11 @@ CODE
|
|||
assert_nil(S("hello").rindex(S("z")))
|
||||
assert_nil(S("hello").rindex(/z./))
|
||||
|
||||
assert_equal(5, S("hello").rindex(S("")))
|
||||
assert_equal(5, S("hello").rindex(S(""), 5))
|
||||
assert_equal(4, S("hello").rindex(S(""), 4))
|
||||
assert_equal(0, S("hello").rindex(S(""), 0))
|
||||
|
||||
o = Object.new
|
||||
def o.to_str; "bar"; end
|
||||
assert_equal(6, S("foobarbarbaz").rindex(o))
|
||||
|
@ -1514,6 +1528,24 @@ CODE
|
|||
assert_equal([3, 3], $~.offset(0))
|
||||
|
||||
assert_equal(5, S("abcdbce").rindex(/b\Kc/))
|
||||
|
||||
assert_equal(2, S("こんにちは").rindex(?に))
|
||||
assert_equal(6, S("にちは、こんにちは").rindex(S("にちは")))
|
||||
assert_equal(6, S("にちは、こんにちは").rindex(/にち./))
|
||||
|
||||
assert_equal(6, S("にちは、こんにちは").rindex(S("にちは"), 7))
|
||||
assert_equal(6, S("にちは、こんにちは").rindex(S("にちは"), -2))
|
||||
assert_equal(6, S("にちは、こんにちは").rindex(S("にちは"), 6))
|
||||
assert_equal(6, S("にちは、こんにちは").rindex(S("にちは"), -3))
|
||||
assert_equal(0, S("にちは、こんにちは").rindex(S("にちは"), 5))
|
||||
assert_equal(0, S("にちは、こんにちは").rindex(S("にちは"), -4))
|
||||
assert_equal(0, S("にちは、こんにちは").rindex(S("にちは"), 1))
|
||||
assert_equal(0, S("にちは、こんにちは").rindex(S("にちは"), 0))
|
||||
|
||||
assert_equal(0, S("こんにちは").rindex(S("こんにちは")))
|
||||
assert_nil(S("こんにち").rindex(S("こんにちは")))
|
||||
assert_nil(S("こ").rindex(S("こんにちは")))
|
||||
assert_nil(S("").rindex(S("こんにちは")))
|
||||
end
|
||||
|
||||
def test_rjust
|
||||
|
@ -3254,6 +3286,114 @@ CODE
|
|||
assert_not_predicate(data, :valid_encoding?)
|
||||
assert_predicate(data[100..-1], :valid_encoding?)
|
||||
end
|
||||
|
||||
def test_byteindex
|
||||
assert_equal(0, S("hello").byteindex(?h))
|
||||
assert_equal(1, S("hello").byteindex(S("ell")))
|
||||
assert_equal(2, S("hello").byteindex(/ll./))
|
||||
|
||||
assert_equal(3, S("hello").byteindex(?l, 3))
|
||||
assert_equal(3, S("hello").byteindex(S("l"), 3))
|
||||
assert_equal(3, S("hello").byteindex(/l./, 3))
|
||||
|
||||
assert_nil(S("hello").byteindex(?z, 3))
|
||||
assert_nil(S("hello").byteindex(S("z"), 3))
|
||||
assert_nil(S("hello").byteindex(/z./, 3))
|
||||
|
||||
assert_nil(S("hello").byteindex(?z))
|
||||
assert_nil(S("hello").byteindex(S("z")))
|
||||
assert_nil(S("hello").byteindex(/z./))
|
||||
|
||||
assert_equal(0, S("").byteindex(S("")))
|
||||
assert_equal(0, S("").byteindex(//))
|
||||
assert_nil(S("").byteindex(S("hello")))
|
||||
assert_nil(S("").byteindex(/hello/))
|
||||
assert_equal(0, S("hello").byteindex(S("")))
|
||||
assert_equal(0, S("hello").byteindex(//))
|
||||
|
||||
s = S("long") * 1000 << "x"
|
||||
assert_nil(s.byteindex(S("y")))
|
||||
assert_equal(4 * 1000, s.byteindex(S("x")))
|
||||
s << "yx"
|
||||
assert_equal(4 * 1000, s.byteindex(S("x")))
|
||||
assert_equal(4 * 1000, s.byteindex(S("xyx")))
|
||||
|
||||
o = Object.new
|
||||
def o.to_str; "bar"; end
|
||||
assert_equal(3, S("foobarbarbaz").byteindex(o))
|
||||
assert_raise(TypeError) { S("foo").byteindex(Object.new) }
|
||||
|
||||
assert_nil(S("foo").byteindex(//, -100))
|
||||
assert_nil($~)
|
||||
|
||||
assert_equal(2, S("abcdbce").byteindex(/b\Kc/))
|
||||
|
||||
assert_equal(0, S("こんにちは").byteindex(?こ))
|
||||
assert_equal(3, S("こんにちは").byteindex(S("んにち")))
|
||||
assert_equal(6, S("こんにちは").byteindex(/にち./))
|
||||
|
||||
assert_equal(0, S("にんにちは").byteindex(?に, 0))
|
||||
assert_raise(IndexError) { S("にんにちは").byteindex(?に, 1) }
|
||||
assert_raise(IndexError) { S("にんにちは").byteindex(?に, 5) }
|
||||
assert_equal(6, S("にんにちは").byteindex(?に, 6))
|
||||
assert_equal(6, S("にんにちは").byteindex(S("に"), 6))
|
||||
assert_equal(6, S("にんにちは").byteindex(/に./, 6))
|
||||
assert_raise(IndexError) { S("にんにちは").byteindex(?に, 7) }
|
||||
end
|
||||
|
||||
def test_byterindex
|
||||
assert_equal(3, S("hello").byterindex(?l))
|
||||
assert_equal(6, S("ell, hello").byterindex(S("ell")))
|
||||
assert_equal(7, S("ell, hello").byterindex(/ll./))
|
||||
|
||||
assert_equal(3, S("hello,lo").byterindex(?l, 3))
|
||||
assert_equal(3, S("hello,lo").byterindex(S("l"), 3))
|
||||
assert_equal(3, S("hello,lo").byterindex(/l./, 3))
|
||||
|
||||
assert_nil(S("hello").byterindex(?z, 3))
|
||||
assert_nil(S("hello").byterindex(S("z"), 3))
|
||||
assert_nil(S("hello").byterindex(/z./, 3))
|
||||
|
||||
assert_nil(S("hello").byterindex(?z))
|
||||
assert_nil(S("hello").byterindex(S("z")))
|
||||
assert_nil(S("hello").byterindex(/z./))
|
||||
|
||||
assert_equal(5, S("hello").byterindex(S("")))
|
||||
assert_equal(5, S("hello").byterindex(S(""), 5))
|
||||
assert_equal(4, S("hello").byterindex(S(""), 4))
|
||||
assert_equal(0, S("hello").byterindex(S(""), 0))
|
||||
|
||||
o = Object.new
|
||||
def o.to_str; "bar"; end
|
||||
assert_equal(6, S("foobarbarbaz").byterindex(o))
|
||||
assert_raise(TypeError) { S("foo").byterindex(Object.new) }
|
||||
|
||||
assert_nil(S("foo").byterindex(//, -100))
|
||||
assert_nil($~)
|
||||
|
||||
assert_equal(3, S("foo").byterindex(//))
|
||||
assert_equal([3, 3], $~.offset(0))
|
||||
|
||||
assert_equal(5, S("abcdbce").byterindex(/b\Kc/))
|
||||
|
||||
assert_equal(6, S("こんにちは").byterindex(?に))
|
||||
assert_equal(18, S("にちは、こんにちは").byterindex(S("にちは")))
|
||||
assert_equal(18, S("にちは、こんにちは").byterindex(/にち./))
|
||||
|
||||
assert_raise(IndexError) { S("にちは、こんにちは").byterindex(S("にちは"), 19) }
|
||||
assert_raise(IndexError) { S("にちは、こんにちは").byterindex(S("にちは"), -2) }
|
||||
assert_equal(18, S("にちは、こんにちは").byterindex(S("にちは"), 18))
|
||||
assert_equal(18, S("にちは、こんにちは").byterindex(S("にちは"), -3))
|
||||
assert_raise(IndexError) { S("にちは、こんにちは").byterindex(S("にちは"), 17) }
|
||||
assert_raise(IndexError) { S("にちは、こんにちは").byterindex(S("にちは"), -4) }
|
||||
assert_raise(IndexError) { S("にちは、こんにちは").byterindex(S("にちは"), 1) }
|
||||
assert_equal(0, S("にちは、こんにちは").byterindex(S("にちは"), 0))
|
||||
|
||||
assert_equal(0, S("こんにちは").byterindex(S("こんにちは")))
|
||||
assert_nil(S("こんにち").byterindex(S("こんにちは")))
|
||||
assert_nil(S("こ").byterindex(S("こんにちは")))
|
||||
assert_nil(S("").byterindex(S("こんにちは")))
|
||||
end
|
||||
end
|
||||
|
||||
class TestString2 < TestString
|
||||
|
|
Loading…
Add table
Reference in a new issue