🚀

[Bug #21102] ASCII 文字列と ASCII 互換文字列を結合した場合のチケット

2025/02/03に公開

[Bug #21102] Unexpected encoding when concatenating ASCII string with ASCII compatible string with non ASCII encoding

  • 次のように ASCII 文字列と ASCII 互換文字列を結合する場合には左辺と右辺の順番によって結果の文字列のエンコーディングが異なります
str = "yakiniku"   # ASCII 互換のエンコーディング

# nil.to_s は ASCII 文字列になる
p nil.to_s.encoding # => #<Encoding:US-ASCII>

# この時に左辺が ASCII の場合は ASCII のエンコーディングの文字列が返ってくる
p (nil.to_s + str).encoding # => #<Encoding:US-ASCII>

# 一方で左辺が ASCII 互換のエンコーディングの場合はそのエンコーディングの文字列が返ってくる
p (str + nil.to_s).encoding # => #<Encoding:UTF-8>
  • 一方で ASCII 文字列に ASCII 非互換の文字列を結合すると左辺と右辺の順番に関わらず ASCII 非互換の文字列のエンコーディングになります
# 両方とも UTF-8 のエンコーディング
str = "焼肉"   # ASCII 非互換のエンコーディング

# nil.to_s は ASCII 文字列になる
p nil.to_s.encoding # => #<Encoding:US-ASCII>

# 左辺と右辺の順番に関わらず ASCII 非互換のエンコーディングになる
p (nil.to_s + str).encoding # => #<Encoding:UTF-8>
p (str + nil.to_s).encoding # => #<Encoding:UTF-8>
  • この挙動が混乱するという内容のチケット
  • Array#join だともう少しわかりやすいと提示もされていますね
str = "yakiniku"

# join する時に nil があると nil の位置によってエンコーディングが異なる可能性がある
p [nil, str].join.encoding # => #<Encoding:US-ASCII>
p [str, nil].join.encoding # => #<Encoding:UTF-8>
  • また似たような話として float や rational の場合も例に出されてますね
# こっちは左辺と右辺が逆でも結果は変わらない
p 1 + 1.0 # => 2.0
p 1.0 + 1 # => 2.0
p 1 + 1r  # => (2/1)
p 1r + 1  # => (2/1)
  • float や rational の例を考えるとどちらかによっているほうが自然な気がしますねえ
GitHubで編集を提案

Discussion