From: "NARUSE, Yui" Date: 2008-01-31T18:54:59+09:00 Subject: [ruby-dev:33550] String#inspect may raise Exception 成瀬です。 > ["\x82\xa0".force_encoding("sjis"), "\xa4\xa2".force_encoding("euc-jp"), "\xe3\x81\x82".force_encoding("utf-8")].inspect ArgumentError: append incompatible encoding strings: Shift_JIS and EUC-JP となります。 思うに、現在 String#inspect は自分自身の encoding と中身のバイト列を比較 して valid ならばエスケープしないという処理を行っていますが、自分自身の encoding でなく、結果となる文字列の encoding を基準とする必要があると思 われます。 つまるところ、inspect が引数に encoding を取る必要があるのですが、 inspect は再帰的に呼ばれるため、ユーザーオブジェクトでも inspect(enc) が 定義されている必要があり、結果的にこのアプローチは事実上不可能です。 新仕様対応の inspect がスレッドローカル変数に期待する encoding をセット するという技もなきにしもあらずですが、現在のマルチバイト文字列をエスケー プなしに出力するという仕様をあきらめざるをえないように感じます。 なお、String#inspect に限って、引数として encoding を取る、というのなら ば、それはいまだ可能ではあります。 --- string.c (revision 15383) +++ string.c (local) @@ -3259,23 +3259,6 @@ return str; } -static void -str_cat_char(VALUE str, int c, rb_encoding *enc) -{ - char s[16]; - int n = rb_enc_codelen(c, enc); - - rb_enc_mbcput(c, s, enc); - rb_enc_str_buf_cat(str, s, n, enc); -} - -static void -prefix_escape(VALUE str, int c, rb_encoding *enc) -{ - str_cat_char(str, '\\', enc); - str_cat_char(str, c, enc); -} - /* * call-seq: * str.inspect => string @@ -3291,81 +3274,65 @@ VALUE rb_str_inspect(VALUE str) { - rb_encoding *enc = STR_ENC_GET(str); char *p, *pend; - VALUE result = rb_str_buf_new2(""); + VALUE result = rb_str_buf_new2("\""); - rb_enc_associate(result, enc); - str_cat_char(result, '"', enc); + ENCODING_CODERANGE_SET(result, rb_usascii_encindex(), ENC_CODERANGE_7BIT); p = RSTRING_PTR(str); pend = RSTRING_END(str); while (p < pend) { - int c; - int n; + int c = *p++; int cc; - n = rb_enc_precise_mbclen(p, pend, enc); - if (!MBCLEN_CHARFOUND_P(n)) { - p++; - n = 1; - goto escape_codepoint; - } - n = MBCLEN_CHARFOUND_LEN(n); - - c = rb_enc_codepoint(p, pend, enc); - n = rb_enc_codelen(c, enc); - - p += n; - if (c == '"'|| c == '\\' || - (c == '#' && + if (c == '#' && p < pend && - 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); + (cc = *(p), + (cc == '$' || cc == '@' || cc == '{'))) { + rb_str_buf_cat2(result, "\\#"); } + else if (c == '"') { + rb_str_buf_cat2(result, "\\\""); + } + else if (c == '\\') { + rb_str_buf_cat2(result, "\\\\"); + } else if (c == '\n') { - prefix_escape(result, 'n', enc); + rb_str_buf_cat2(result, "\\n"); } else if (c == '\r') { - prefix_escape(result, 'r', enc); + rb_str_buf_cat2(result, "\\r"); } else if (c == '\t') { - prefix_escape(result, 't', enc); + rb_str_buf_cat2(result, "\\t"); } else if (c == '\f') { - prefix_escape(result, 'f', enc); + rb_str_buf_cat2(result, "\\f"); } else if (c == '\013') { - prefix_escape(result, 'v', enc); + rb_str_buf_cat2(result, "\\v"); } else if (c == '\010') { - prefix_escape(result, 'b', enc); + rb_str_buf_cat2(result, "\\b"); } else if (c == '\007') { - prefix_escape(result, 'a', enc); + rb_str_buf_cat2(result, "\\a"); } else if (c == 033) { - prefix_escape(result, 'e', enc); + rb_str_buf_cat2(result, "\\e"); } - else if (rb_enc_isprint(c, enc)) { - rb_enc_str_buf_cat(result, p-n, n, enc); - } else { char buf[5]; char *s; char *q; escape_codepoint: - for (q = p-n; q < p; q++) { + for (q = p-1; q < p; q++) { s = buf; sprintf(buf, "\\x%02X", *q & 0377); - while (*s) { - str_cat_char(result, *s++, enc); - } + rb_str_buf_cat2(result, s); } } } - str_cat_char(result, '"', enc); + rb_str_buf_cat2(result, "\""); OBJ_INFECT(result, str); return result; -- NARUSE, Yui DBDB A476 FDBD 9450 02CD 0EFC BCE3 C388 472E C1EA