diff options
Diffstat (limited to 'mrbgems/mruby-string-ext')
| -rw-r--r-- | mrbgems/mruby-string-ext/mrblib/string.rb | 73 | ||||
| -rw-r--r-- | mrbgems/mruby-string-ext/src/string.c | 130 |
2 files changed, 73 insertions, 130 deletions
diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 39ee57419..27ca30610 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -386,4 +386,77 @@ class String end lines end + + ## + # call-seq: + # str.upto(other_str, exclusive=false) {|s| block } -> str + # str.upto(other_str, exclusive=false) -> an_enumerator + # + # Iterates through successive values, starting at <i>str</i> and + # ending at <i>other_str</i> inclusive, passing each value in turn to + # the block. The <code>String#succ</code> method is used to generate + # each value. If optional second argument exclusive is omitted or is false, + # the last value will be included; otherwise it will be excluded. + # + # If no block is given, an enumerator is returned instead. + # + # "a8".upto("b6") {|s| print s, ' ' } + # for s in "a8".."b6" + # print s, ' ' + # end + # + # <em>produces:</em> + # + # a8 a9 b0 b1 b2 b3 b4 b5 b6 + # a8 a9 b0 b1 b2 b3 b4 b5 b6 + # + # If <i>str</i> and <i>other_str</i> contains only ascii numeric characters, + # both are recognized as decimal numbers. In addition, the width of + # string (e.g. leading zeros) is handled appropriately. + # + # "9".upto("11").to_a #=> ["9", "10", "11"] + # "25".upto("5").to_a #=> [] + # "07".upto("11").to_a #=> ["07", "08", "09", "10", "11"] + def upto(max, exclusive=false, &block) + return to_enum(:upto, max, exclusive) unless block + raise TypeError, "no implicit conversion of #{max.class} into String" unless max.kind_of? String + + len = self.length + maxlen = max.length + # single character + if len == 1 and maxlen == 1 + c = self.ord + e = max.ord + while c <= e + break if exclusive and c == e + yield c.chr + c += 1 + end + return self + end + # both edges are all digits + bi = self.to_i(10) + ei = max.to_i(10) + len = self.length + if (bi > 0 or bi == "0"*len) and (ei > 0 or ei == "0"*maxlen) + while bi <= ei + break if exclusive and bi == ei + s = bi.to_s + s = s.rjust(len, "0") if s.length < len + yield s + bi += 1 + end + return self + end + bs = self + while true + n = (bs <=> max) + break if n > 0 + break if exclusive and n == 0 + yield bs + break if n == 0 + bs = bs.succ + end + self + end end diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 48fa27085..4cab49094 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -470,135 +470,6 @@ mrb_str_ord(mrb_state* mrb, mrb_value str) } #endif -static mrb_bool -all_digits_p(const char *s, mrb_int len) -{ - while (len-- > 0) { - if (!ISDIGIT(*s)) return FALSE; - s++; - } - return TRUE; -} - -/* - * call-seq: - * str.upto(other_str, exclusive=false) {|s| block } -> str - * str.upto(other_str, exclusive=false) -> an_enumerator - * - * Iterates through successive values, starting at <i>str</i> and - * ending at <i>other_str</i> inclusive, passing each value in turn to - * the block. The <code>String#succ</code> method is used to generate - * each value. If optional second argument exclusive is omitted or is false, - * the last value will be included; otherwise it will be excluded. - * - * If no block is given, an enumerator is returned instead. - * - * "a8".upto("b6") {|s| print s, ' ' } - * for s in "a8".."b6" - * print s, ' ' - * end - * - * <em>produces:</em> - * - * a8 a9 b0 b1 b2 b3 b4 b5 b6 - * a8 a9 b0 b1 b2 b3 b4 b5 b6 - * - * If <i>str</i> and <i>other_str</i> contains only ascii numeric characters, - * both are recognized as decimal numbers. In addition, the width of - * string (e.g. leading zeros) is handled appropriately. - * - * "9".upto("11").to_a #=> ["9", "10", "11"] - * "25".upto("5").to_a #=> [] - * "07".upto("11").to_a #=> ["07", "08", "09", "10", "11"] - */ -static mrb_value -mrb_str_upto(mrb_state *mrb, mrb_value beg) -{ - mrb_value end; - mrb_value exclusive = mrb_false_value(); - mrb_value block = mrb_nil_value(); - mrb_value current, after_end; - mrb_int n; - mrb_bool excl; - - mrb_get_args(mrb, "o|o&", &end, &exclusive, &block); - - if (mrb_nil_p(block)) { - return mrb_funcall(mrb, beg, "to_enum", 3, mrb_symbol_value(mrb_intern_lit(mrb, "upto")), end, exclusive); - } - end = mrb_string_type(mrb, end); - excl = mrb_test(exclusive); - - /* single character */ - if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && - ISASCII(RSTRING_PTR(beg)[0]) && ISASCII(RSTRING_PTR(end)[0])) { - char c = RSTRING_PTR(beg)[0]; - char e = RSTRING_PTR(end)[0]; - int ai = mrb_gc_arena_save(mrb); - - if (c > e || (excl && c == e)) return beg; - for (;;) { - mrb_yield(mrb, block, mrb_str_new(mrb, &c, 1)); - mrb_gc_arena_restore(mrb, ai); - if (!excl && c == e) break; - c++; - if (excl && c == e) break; - } - return beg; - } - /* both edges are all digits */ - if (ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) && - all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) && - all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) { - mrb_int min_width = RSTRING_LEN(beg); - mrb_int bi = mrb_int(mrb, mrb_str_to_inum(mrb, beg, 10, FALSE)); - mrb_int ei = mrb_int(mrb, mrb_str_to_inum(mrb, end, 10, FALSE)); - int ai = mrb_gc_arena_save(mrb); - - while (bi <= ei) { - mrb_value ns, str; - - if (excl && bi == ei) break; - ns = mrb_format(mrb, "%S", mrb_fixnum_value(bi)); - if (min_width > RSTRING_LEN(ns)) { - str = mrb_str_new(mrb, NULL, min_width); - memset(RSTRING_PTR(str), '0', min_width-RSTRING_LEN(ns)); - memcpy(RSTRING_PTR(str)+min_width-RSTRING_LEN(ns), - RSTRING_PTR(ns), RSTRING_LEN(ns)); - } - else { - str = ns; - } - mrb_yield(mrb, block, str); - mrb_gc_arena_restore(mrb, ai); - bi++; - } - - return beg; - } - /* normal case */ - n = mrb_int(mrb, mrb_funcall(mrb, beg, "<=>", 1, end)); - if (n > 0 || (excl && n == 0)) return beg; - - after_end = mrb_funcall(mrb, end, "succ", 0); - current = mrb_str_dup(mrb, beg); - while (!mrb_str_equal(mrb, current, after_end)) { - int ai = mrb_gc_arena_save(mrb); - mrb_value next = mrb_nil_value(); - if (excl || !mrb_str_equal(mrb, current, end)) - next = mrb_funcall(mrb, current, "succ", 0); - mrb_yield(mrb, block, current); - if (mrb_nil_p(next)) break; - current = mrb_str_to_str(mrb, next); - if (excl && mrb_str_equal(mrb, current, end)) break; - if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0) - break; - mrb_gc_arena_restore(mrb, ai); - } - - return beg; -} - /* * call-seq: * str.delete_prefix!(prefix) -> self or nil @@ -759,7 +630,6 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ")); mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!")); mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE()); - mrb_define_method(mrb, s, "upto", mrb_str_upto, MRB_ARGS_ANY()); mrb_define_method(mrb, s, "delete_prefix!", mrb_str_del_prefix_bang, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "delete_prefix", mrb_str_del_prefix, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "delete_suffix!", mrb_str_del_suffix_bang, MRB_ARGS_REQ(1)); |
