[前][次][番号順一覧][スレッド一覧]

ruby-changes:44899

From: nobu <ko1@a...>
Date: Sat, 3 Dec 2016 23:18:08 +0900 (JST)
Subject: [ruby-changes:44899] nobu:r56972 (trunk): string.c: chomp option

nobu	2016-12-03 23:18:03 +0900 (Sat, 03 Dec 2016)

  New Revision: 56972

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=56972

  Log:
    string.c: chomp option
    
    * string.c (rb_str_enumerate_lines): implement chomp option.

  Modified files:
    trunk/string.c
    trunk/test/ruby/test_string.rb
Index: string.c
===================================================================
--- string.c	(revision 56971)
+++ string.c	(revision 56972)
@@ -7376,22 +7376,41 @@ rb_str_split(VALUE str, const char *sep0 https://github.com/ruby/ruby/blob/trunk/string.c#L7376
     return rb_str_split_m(1, &sep, str);
 }
 
+static const char *
+chomp_newline(const char *p, const char *e, rb_encoding *enc)
+{
+    const char *prev = rb_enc_prev_char(p, e, e, enc);
+    if (rb_enc_is_newline(prev, e, enc)) {
+	e = prev;
+	prev = rb_enc_prev_char(p, e, e, enc);
+	if (rb_enc_ascget(prev, e, NULL, enc) == '\r')
+	    e = prev;
+    }
+    return e;
+}
 
 static VALUE
 rb_str_enumerate_lines(int argc, VALUE *argv, VALUE str, int wantarray)
 {
     rb_encoding *enc;
-    VALUE line, rs, orig = str;
+    VALUE line, rs, orig = str, opts = Qnil, chomp = Qfalse;
     const char *ptr, *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
     long pos, len, rslen;
     int paragraph_mode = 0;
+    int rsnewline = 0;
 
     VALUE MAYBE_UNUSED(ary);
 
-    if (argc == 0)
+    if (rb_scan_args(argc, argv, "01:", &rs, &opts) == 0)
 	rs = rb_rs;
-    else
-	rb_scan_args(argc, argv, "01", &rs);
+    if (!NIL_P(opts)) {
+	static ID keywords[1];
+	if (!keywords[0]) {
+	    keywords[0] = rb_intern_const("chomp");
+	}
+	rb_get_kwargs(opts, keywords, 0, 1, &chomp);
+	chomp = (chomp != Qundef && RTEST(chomp));
+    }
 
     if (rb_block_given_p()) {
 	if (wantarray) {
@@ -7438,9 +7457,14 @@ rb_str_enumerate_lines(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/string.c#L7457
 	rsptr = "\n\n";
 	rslen = 2;
 	paragraph_mode = 1;
+	rsnewline = 1;
     }
     else {
 	rsptr = RSTRING_PTR(rs);
+	if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
+	    rb_enc_is_newline(rsptr, rsptr + RSTRING_LEN(rs), enc)) {
+	    rsnewline = 1;
+	}
     }
 
     if ((rs == rb_default_rs || paragraph_mode) && !rb_enc_asciicompat(enc)) {
@@ -7461,10 +7485,24 @@ rb_str_enumerate_lines(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/string.c#L7485
 	}
 	subend = hit + rslen;
 	if (paragraph_mode) {
-	    while (subend < pend && rb_enc_is_newline(subend, pend, enc)) {
+	    while (subend < pend) {
+		int n;
+		if (rb_enc_ascget(subend, pend, &n, enc) != '\r')
+		    n = 0;
+		if (!rb_enc_is_newline(subend + n, pend, enc)) break;
+		subend += n;
 		subend += rb_enc_mbclen(subend, pend, enc);
 	    }
 	}
+	hit = subend;
+	if (chomp) {
+	    if (rsnewline) {
+		subend = chomp_newline(subptr, subend, enc);
+	    }
+	    else {
+		subend -= rslen;
+	    }
+	}
 	line = rb_str_subseq(str, subptr - ptr, subend - subptr);
 	if (wantarray) {
 	    rb_ary_push(ary, line);
@@ -7473,10 +7511,13 @@ rb_str_enumerate_lines(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/string.c#L7511
 	    rb_yield(line);
 	    str_mod_check(str, ptr, len);
 	}
-	subptr = subend;
+	subptr = hit;
     }
 
     if (subptr != pend) {
+	if (chomp && paragraph_mode) {
+	    pend = chomp_newline(subptr, pend, enc);
+	}
 	line = rb_str_subseq(str, subptr - ptr, pend - subptr);
 	if (wantarray)
 	    rb_ary_push(ary, line);
Index: test/ruby/test_string.rb
===================================================================
--- test/ruby/test_string.rb	(revision 56971)
+++ test/ruby/test_string.rb	(revision 56972)
@@ -816,6 +816,35 @@ CODE https://github.com/ruby/ruby/blob/trunk/test/ruby/test_string.rb#L816
     $/ = save
   end
 
+  def test_each_line_chomp
+    res = []
+    S("hello\nworld").each_line("\n", chomp: true) {|x| res << x}
+    assert_equal(S("hello"), res[0])
+    assert_equal(S("world"), res[1])
+
+    res = []
+    S("hello\n\n\nworld").each_line(S(''), chomp: true) {|x| res << x}
+    assert_equal(S("hello\n\n"), res[0])
+    assert_equal(S("world"),     res[1])
+
+    res = []
+    S("hello!world").each_line(S('!'), chomp: true) {|x| res << x}
+    assert_equal(S("hello"), res[0])
+    assert_equal(S("world"), res[1])
+
+    res = []
+    S("a").each_line(S('ab'), chomp: true).each {|x| res << x}
+    assert_equal(1, res.size)
+    assert_equal(S("a"), res[0])
+
+    s = nil
+    "foo\nbar".each_line(nil, chomp: true) {|s2| s = s2 }
+    assert_equal("foo\nbar", s)
+
+    assert_equal "hello", S("hello\nworld").each_line(chomp: true).next
+    assert_equal "hello\nworld", S("hello\nworld").each_line(nil, chomp: true).next
+  end
+
   def test_lines
     s = S("hello\nworld")
     assert_equal ["hello\n", "world"], s.lines

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]