From: "naruse (Yui NARUSE)" Date: 2012-07-22T03:20:33+09:00 Subject: [ruby-dev:45992] [ruby-trunk - Feature #6767][Assigned] Utility method to get a duplicated string whose encoding is ASCII-8BIT Issue #6767 has been reported by naruse (Yui NARUSE). ---------------------------------------- Feature #6767: Utility method to get a duplicated string whose encoding is ASCII-8BIT https://bugs.ruby-lang.org/issues/6767 Author: naruse (Yui NARUSE) Status: Assigned Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: 2.0.0 ある String を ASCII-8BIT にしたいことはしばしばあります。 それだけならばまだ force_encoding しろよという話なのですが、 #6361 の例のように、バイナリ文字列にさらにバイナリ文字列を結合していく場合、 毎行毎行 force_encoding を書いていくのにはつらいものがあります。 解決案としては、 (1) バイナリリテラルの導入 (2) dup.force_encoding(Encoding::ASCII_8BIT) する短いメソッドを追加 (3) ASCII-8BIT に他のエンコーディングの文字列を結合した場合は暗黙に force_encoding が考えられます。 しかし、(1) は文法拡張なのでハードルが高く、(3) は方々で議論になっている通りです。 よって、(2) が妥当ではないかと思います。 名前をまつもとさん提案の String#b としたパッチを以下の通り添付します。 diff --git a/string.c b/string.c index d038835..76cbc36 100644 --- a/string.c +++ b/string.c @@ -601,7 +601,7 @@ rb_str_export_to_enc(VALUE str, rb_encoding *enc) } static VALUE -str_replace_shared(VALUE str2, VALUE str) +str_replace_shared_without_enc(VALUE str2, VALUE str) { if (RSTRING_LEN(str) <= RSTRING_EMBED_LEN_MAX) { STR_SET_EMBED(str2); @@ -616,8 +616,14 @@ str_replace_shared(VALUE str2, VALUE str) RSTRING(str2)->as.heap.aux.shared = str; FL_SET(str2, ELTS_SHARED); } - rb_enc_cr_str_exact_copy(str2, str); + return str2; +} +static VALUE +str_replace_shared(VALUE str2, VALUE str) +{ + str_replace_shared_without_enc(str2, str); + rb_enc_cr_str_exact_copy(str2, str); return str2; } @@ -7340,6 +7346,23 @@ rb_str_force_encoding(VALUE str, VALUE enc) /* * call-seq: + * str.b -> str + * + * Returns a copied string whose encoding is ASCII-8BIT. + */ + +static VALUE +rb_str_b(VALUE str) +{ + VALUE str2 = str_alloc(rb_cString); + str_replace_shared_without_enc(str2, str); + OBJ_INFECT(str2, str); + ENC_CODERANGE_SET(str2, ENC_CODERANGE_VALID); + return str2; +} + +/* + * call-seq: * str.valid_encoding? -> true or false * * Returns true for a string which encoded correctly. @@ -7969,6 +7992,7 @@ Init_String(void) rb_define_method(rb_cString, "encoding", rb_obj_encoding, 0); /* in encoding.c */ rb_define_method(rb_cString, "force_encoding", rb_str_force_encoding, 1); + rb_define_method(rb_cString, "b", rb_str_b, 0); rb_define_method(rb_cString, "valid_encoding?", rb_str_valid_encoding_p, 0); rb_define_method(rb_cString, "ascii_only?", rb_str_is_ascii_only_p, 0); diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb index dfcaa94..3a4bca7 100644 --- a/test/ruby/test_m17n.rb +++ b/test/ruby/test_m17n.rb @@ -1469,4 +1469,14 @@ class TestM17N < Test::Unit::TestCase yield(*strs) end end + + def test_str_b + s = "\u3042" + assert_equal(a("\xE3\x81\x82"), s.b) + assert_equal(Encoding::ASCII_8BIT, s.b.encoding) + s.taint + assert_equal(true, s.b.tainted?) + s.untrust + assert_equal(true, s.b.untrusted?) + end end -- http://bugs.ruby-lang.org/