ruby-changes:4505
From: ko1@a...
Date: Mon, 14 Apr 2008 13:16:37 +0900 (JST)
Subject: [ruby-changes:4505] knu - Ruby:r15998 (ruby_1_8): * string.c (rb_str_partition, rb_str_rpartition,
knu 2008-04-14 13:16:23 +0900 (Mon, 14 Apr 2008) New Revision: 15998 Modified files: branches/ruby_1_8/ChangeLog branches/ruby_1_8/NEWS branches/ruby_1_8/string.c Log: * string.c (rb_str_partition, rb_str_rpartition, rb_str_start_with, rb_str_end_with): New methods: String#partition, #rpartition, #start_with? and #end_with?; backported from 1.9. These methods are $KCODE aware unlike #index, #rindex and #include?. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ChangeLog?r1=15998&r2=15997&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/NEWS?r1=15998&r2=15997&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/string.c?r1=15998&r2=15997&diff_format=u Index: ruby_1_8/NEWS =================================================================== --- ruby_1_8/NEWS (revision 15997) +++ ruby_1_8/NEWS (revision 15998) @@ -70,6 +70,14 @@ * Regexp.union accepts an array of patterns. + * String#partition + * String#rpartition + * String#start_with? + * String#end_with? + + New methods. These are $KCODE aware unlike #index, #rindex and + #include?. + * StopIteration New exception class that causes Kernel#loop to stop iteration when Index: ruby_1_8/ChangeLog =================================================================== --- ruby_1_8/ChangeLog (revision 15997) +++ ruby_1_8/ChangeLog (revision 15998) @@ -1,3 +1,16 @@ +Mon Apr 14 13:07:59 2008 Akinori MUSHA <knu@i...> + + * string.c (rb_str_partition, rb_str_rpartition, + rb_str_start_with, rb_str_end_with): New methods: + String#partition, #rpartition, #start_with? and #end_with?; + backported from 1.9. These methods are $KCODE aware unlike + #index, #rindex and #include?. + +Mon Apr 14 00:11:22 2008 Akinori MUSHA <knu@i...> + + * struct.c (rb_struct_each, rb_struct_each_pair): Return + an enumerator if no block is given. + Sun Apr 13 15:55:52 2008 Kazuhiro NISHIYAMA <zn@m...> * object.c (sym_to_proc): new method Symbol#to_proc; backported Index: ruby_1_8/string.c =================================================================== --- ruby_1_8/string.c (revision 15997) +++ ruby_1_8/string.c (revision 15998) @@ -1941,7 +1941,31 @@ return rb_reg_regcomp(pat); } +static VALUE +get_pat_quoted(pat) + VALUE pat; +{ + return get_pat(pat, 1); +} +static VALUE +regcomp_failed(str) + VALUE str; +{ + rb_raise(rb_eArgError, "invalid byte sequence"); + /*NOTREACHED*/ + return Qundef; +} + +static VALUE +get_arg_pat(pat, quote) + VALUE pat; +{ + return rb_rescue2(get_pat_quoted, pat, + regcomp_failed, pat, + rb_eRegexpError, (VALUE)0); +} + /* * call-seq: * str.sub!(pattern, replacement) => str or nil @@ -4718,6 +4742,151 @@ return rb_str_justify(argc, argv, str, 'c'); } +/* + * call-seq: + * str.partition(sep) => [head, sep, tail] + * + * Searches the string for <i>sep</i> and returns the part before it, + * the <i>sep</i>, and the part after it. If <i>sep</i> is not + * found, returns <i>str</i> and two empty strings. If no argument + * is given, Enumerable#partition is called. + * + * "hello".partition("l") #=> ["he", "l", "lo"] + * "hello".partition("x") #=> ["hello", "", ""] + */ + +static VALUE +rb_str_partition(argc, argv, str) + int argc; + VALUE *argv; + VALUE str; +{ + VALUE sep; + long pos; + + if (argc == 0) return rb_call_super(argc, argv); + rb_scan_args(argc, argv, "1", &sep); + if (TYPE(sep) != T_REGEXP) { + VALUE tmp; + + tmp = rb_check_string_type(sep); + if (NIL_P(tmp)) { + rb_raise(rb_eTypeError, "type mismatch: %s given", + rb_obj_classname(sep)); + } + sep = get_arg_pat(tmp); + } + pos = rb_reg_search(sep, str, 0, 0); + if (pos < 0) { + failed: + return rb_ary_new3(3, str, rb_str_new(0,0),rb_str_new(0,0)); + } + sep = rb_str_subpat(str, sep, 0); + if (pos == 0 && RSTRING(sep)->len == 0) goto failed; + return rb_ary_new3(3, rb_str_substr(str, 0, pos), + sep, + rb_str_substr(str, pos+RSTRING(sep)->len, + RSTRING(str)->len-pos-RSTRING(sep)->len)); +} + +/* + * call-seq: + * str.rpartition(sep) => [head, sep, tail] + * + * Searches <i>sep</i> in the string from the end of the string, and + * returns the part before it, the <i>sep</i>, and the part after it. + * If <i>sep</i> is not found, returns two empty strings and + * <i>str</i>. + * + * "hello".rpartition("l") #=> ["hel", "l", "o"] + * "hello".rpartition("x") #=> ["", "", "hello"] + */ + +static VALUE +rb_str_rpartition(str, sep) + VALUE str; + VALUE sep; +{ + long pos = RSTRING(str)->len; + + if (TYPE(sep) != T_REGEXP) { + VALUE tmp; + + tmp = rb_check_string_type(sep); + if (NIL_P(tmp)) { + rb_raise(rb_eTypeError, "type mismatch: %s given", + rb_obj_classname(sep)); + } + sep = get_arg_pat(tmp); + } + pos = rb_reg_search(sep, str, pos, 1); + if (pos < 0) { + return rb_ary_new3(3, rb_str_new(0,0),rb_str_new(0,0), str); + } + sep = rb_reg_nth_match(0, rb_backref_get()); + return rb_ary_new3(3, rb_str_substr(str, 0, pos), + sep, + rb_str_substr(str, pos+RSTRING(sep)->len, + RSTRING(str)->len-pos-RSTRING(sep)->len)); +} + +/* + * call-seq: + * str.start_with?([prefix]+) => true or false + * + * Returns true if <i>str</i> starts with the prefix given. + */ + +static VALUE +rb_str_start_with(argc, argv, str) + int argc; + VALUE *argv; + VALUE str; +{ + int i; + long pos; + VALUE pat; + + for (i=0; i<argc; i++) { + VALUE prefix = rb_check_string_type(argv[i]); + if (NIL_P(prefix)) continue; + if (RSTRING(str)->len < RSTRING(prefix)->len) continue; + pat = get_arg_pat(prefix); + if (rb_reg_search(pat, str, 0, 1) >= 0) + return Qtrue; + } + return Qfalse; +} + +/* + * call-seq: + * str.end_with?([suffix]+) => true or false + * + * Returns true if <i>str</i> ends with the suffix given. + */ + +static VALUE +rb_str_end_with(argc, argv, str) + int argc; + VALUE *argv; + VALUE str; +{ + int i; + long pos; + VALUE pat; + + for (i=0; i<argc; i++) { + VALUE suffix = rb_check_string_type(argv[i]); + if (NIL_P(suffix)) continue; + if (RSTRING(str)->len < RSTRING(suffix)->len) continue; + pat = get_arg_pat(suffix); + pos = rb_reg_adjust_startpos(pat, str, RSTRING(str)->len - RSTRING(suffix)->len, 0); + if (rb_reg_search(pat, str, pos, 0) >= 0) + return Qtrue; + } + return Qfalse; +} + void rb_str_setter(val, id, var) VALUE val; @@ -4807,6 +4976,8 @@ rb_define_method(rb_cString, "to_sym", rb_str_intern, 0); rb_define_method(rb_cString, "include?", rb_str_include, 1); + rb_define_method(rb_cString, "start_with?", rb_str_start_with, -1); + rb_define_method(rb_cString, "end_with?", rb_str_end_with, -1); rb_define_method(rb_cString, "scan", rb_str_scan, 1); @@ -4868,6 +5039,9 @@ rb_define_method(rb_cString, "slice", rb_str_aref_m, -1); rb_define_method(rb_cString, "slice!", rb_str_slice_bang, -1); + rb_define_method(rb_cString, "partition", rb_str_partition, -1); + rb_define_method(rb_cString, "rpartition", rb_str_rpartition, 1); + id_to_s = rb_intern("to_s"); rb_fs = Qnil; -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/