鯨飲馬食

いろいろつまみ食いで勉強したことのメモ書き

文字列の内部表現

クイズ

Pythonクイズ 文字列中に含まれる a という1文字が消費するメモリサイズは?

  1. 1バイト
  2. 2バイト
  3. 3バイト
  4. 4バイト
  5. わからない

こういう問いかけをSlack上でしたところ、「1. 1バイト」と答えた人が9名、「5. わからない」と答えた人が4名でした。

出題意図としては、「5. わからない」あるいは、「1. 1バイト」&「2. 2バイト」&「4. 4バイト」の3つを選択してくれたなら正解のつもりだったので、4名が正解。

Python: PEP-393

www.python.org

Python 3.3 以降における文字列の内部表現は、latin-1 or UCS-2 or UCS-4 のいずれかが用いられる。どれが用いられるかは文字列中の文字のコードポイントの最大値で決まる。256未満ならlatin-1配列(1文字1バイト)、65536未満ならUCS-2配列(1文字2バイト)、それ以外ならUCS-4配列(1文字4バイト)

CPythonの実装は

cpython/unicodeobject.c at 0d7f61ddb074659d8c18c8f5ac86a6a18e41f9e5 · python/cpython · GitHub

で、NULL終端の分も含めて (size + 1) * char_size 分のメモリを文字列格納用に確保している。

クイズの答えはpython REPL上で以下のように確認できる:

>>> import sys
>>> X = "abc"
>>> sys.getsizeof(X + "a") - sys.getsizeof(X)
1
>>> X = "abcあ"
>>> sys.getsizeof(X + "a") - sys.getsizeof(X)
2
>>> X = "abcあ\U00029e3d"
>>> X
'abcあ𩸽'
>>> sys.getsizeof(X + "a") - sys.getsizeof(X)
4
>>>

他の言語処理系では

ついでにPython以外だとどうなのか調べてみたら、いろいろあることがわかった。

Rubyはバイト列とエンコーディングの組み合わせで文字列を表現しているとのこと。

techracho.bpsinc.jp

.NET は UTF-16

docs.microsoft.com

JavaUTF-16 だけど、Java9以降では1文字1バイトに収まる時はlatin-1で表現しているとのこと。知らなかった。

yujisoftware.hatenablog.com

Goの string は UTF-8

text.baldanders.info