Project

General

Profile

Feature #2102

String#inspect as default_internal encoding

Added by naruse (Yui NARUSE) almost 10 years ago. Updated over 8 years ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-dev:39343]

Description

=begin
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;
    =end

History

#1

Updated by matz (Yukihiro Matsumoto) almost 10 years ago

=begin
まつもと ゆきひろです

In message "Re: [ruby-dev:39343] [Feature #2102] String#inspect as default_internal encoding"
on Wed, 16 Sep 2009 01:11:39 +0900, Yui NARUSE redmine@ruby-lang.org writes:

|String#inspect の結果は特定のエンコーディングに揃えるようにしませんか。

<略>

その方が便利そうですね。コミットしてください。

=end

#2

Updated by naruse (Yui NARUSE) almost 10 years ago

  • Status changed from Open to Closed

=begin
r25113で反映しました。
=end

Also available in: Atom PDF