From: Yui NARUSE <redmine@...> Date: 2009-09-16T01:11:39+09:00 Subject: [ruby-dev:39343] [Feature #2102] String#inspect as default_internal encoding Feature #2102: String#inspect as default_internal encoding http://redmine.ruby-lang.org/issues/show/2102 起票者: Yui NARUSE ステータス: Open, 優先度: Normal カテゴリ: M17N String#inspect の結果は特定のエンコーディングに揃えるようにしませんか。 現在の inspect は異なるエンコーディングを持つ文字列でも何も考えず結合を試み、 結果 EncodingCompatibilityError が上がったとしても気にしない、 というものになっています。 しかし、inspect は irb や p など、とりあえずオブジェクトの中身を概観したい、 という時に使われるものなのに、異なるエンコーディングがあるくらいで、 例外になってしまうは正直不便です。 添付のパッチでは、 * default_internal が設定されていればそれを、設定されていなければ default_external を用いる。 ただし、そのエンコーディングが ASCII compatible でない場合は US-ASCII を用いる。 (以下 inspect のエンコーディングと呼ぶ) * String#inspect の結果は、その String のエンコーディングが、 inspect のエンコーディングと同じ場合はこれまでと同様。 * 異なる場合、String 内の非 US-ASCII 文字は \xXX 形式でエスケープする。 * String 以外の inspect はこれまでと同様。 としています。 これにより、inspect 結果のエンコーディングが一定になるので例外が上がることがなくなります。 動作の例を示すと、inspect のエンコーディングが UTF-8 の場合、 "あ".encode("UTF-16BE").inspect # before => "0B" # after => "\x30\x42" "い".encode("UTF-8").inspect # before => "い" # after => "い" "う".encode("EUC-JP").inspect # before => "" (注: EUC-JP で生の「う」) # after => "\xA4\xA6" ["あ".encode("UTF-16BE"), "い".encode("UTF-8"), "う".encode("EUC-JP")].inspect # before=> EncodingCompatibilityError # after => ["\x30\x42", "い", "\xA4\xA6"] どうでしょうか? diff --git a/string.c b/string.c index aa36c37..b8d862c 100644 --- a/string.c +++ b/string.c @@ -1739,6 +1739,12 @@ str_buf_cat(VALUE str, const char *ptr, long len) return str; } +static VALUE +str_buf_cat2(VALUE str, const char *ptr) +{ + return str_buf_cat(str, ptr, strlen(ptr)); +} + VALUE rb_str_buf_cat(VALUE str, const char *ptr, long len) { @@ -4237,13 +4243,6 @@ str_cat_char(VALUE str, unsigned int c, rb_encoding *enc) rb_enc_str_buf_cat(str, s, n, enc); } -static void -prefix_escape(VALUE str, unsigned int c, rb_encoding *enc) -{ - str_cat_char(str, '\\', enc); - str_cat_char(str, c, enc); -} - /* * call-seq: * str.inspect => string @@ -4262,10 +4261,13 @@ rb_str_inspect(VALUE str) rb_encoding *enc = STR_ENC_GET(str); char *p, *pend; VALUE result = rb_str_buf_new(0); + rb_encoding *resenc = rb_default_internal_encoding(); + + if (resenc == NULL) resenc = rb_default_external_encoding(); + if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding(); + rb_enc_associate(result, resenc); + str_buf_cat2(result, "\""); - if (!rb_enc_asciicompat(enc)) enc = rb_usascii_encoding(); - rb_enc_associate(result, enc); - str_cat_char(result, '"', enc); p = RSTRING_PTR(str); pend = RSTRING_END(str); while (p < pend) { unsigned int c, cc; @@ -4278,8 +4280,7 @@ rb_str_inspect(VALUE str) goto escape_codepoint; } n = MBCLEN_CHARFOUND_LEN(n); - - c = rb_enc_codepoint_len(p, pend, &n, enc); + c = rb_enc_mbc_to_codepoint(p, pend, enc); p += n; if (c == '"'|| c == '\\' || (c == '#' && @@ -4287,51 +4288,49 @@ rb_str_inspect(VALUE str) MBCLEN_CHARFOUND_P(rb_enc_precise_mbclen(p,pend,enc)) && (cc = rb_enc_codepoint(p,pend,enc), (cc == '$' || cc == '@' || cc == '{')))) { - prefix_escape(result, c, enc); + str_buf_cat2(result, "\\"); + str_buf_cat(result, p - n, n); } else if (c == '\n') { - prefix_escape(result, 'n', enc); + str_buf_cat2(result, "\\n"); } else if (c == '\r') { - prefix_escape(result, 'r', enc); + str_buf_cat2(result, "\\r"); } else if (c == '\t') { - prefix_escape(result, 't', enc); + str_buf_cat2(result, "\\t"); } else if (c == '\f') { - prefix_escape(result, 'f', enc); + str_buf_cat2(result, "\\f"); } else if (c == '\013') { - prefix_escape(result, 'v', enc); + str_buf_cat2(result, "\\v"); } else if (c == '\010') { - prefix_escape(result, 'b', enc); + str_buf_cat2(result, "\\b"); } else if (c == '\007') { - prefix_escape(result, 'a', enc); + str_buf_cat2(result, "\\a"); } else if (c == 033) { - prefix_escape(result, 'e', enc); + str_buf_cat2(result, "\\e"); } - else if (rb_enc_isprint(c, enc)) { - rb_enc_str_buf_cat(result, p-n, n, enc); + else if ((enc == resenc && rb_enc_isprint(c, enc)) || rb_enc_isascii(c, enc)) { + str_buf_cat(result, p-n, n); } else { - char buf[5]; - char *s; char *q; - escape_codepoint: for (q = p-n; q < p; q++) { - s = buf; - sprintf(buf, "\\x%02X", *q & 0377); - while (*s) { - str_cat_char(result, *s++, enc); - } - } +#define BACKESC_BUFSIZE 5 + char buf[BACKESC_BUFSIZE]; + sprintf(buf, "\\x%02X", *q & 0377); + str_buf_cat(result, buf, BACKESC_BUFSIZE - 1); +#undef BACKESC_BUFSIZE + } } } - str_cat_char(result, '"', enc); + str_buf_cat2(result, "\""); OBJ_INFECT(result, str); return result; ---------------------------------------- http://redmine.ruby-lang.org