🙌

[Feature #20594] エンコーディングを維持しながらバイト列を追加する String#byteconcat

2024/06/30に公開

[Feature #20594] A new String method to append bytes while preserving encoding

  • エンコーディングを維持しながらバイト列を追加する String#byteconcat メソッドの提案
  • profobufMessagePack などのバイナリプロトコルを利用する場合に以下のようにシリアライズする
Post = Struct.new(:title, :body) do
  def serialize(buf)
    buf <<
    255 << title.bytesize << title <<
    255 << body.bytesize << body
  end
end

Post.new("Hello", "World").serialize("somedata".b)
# => "somedata\xFF\x05Hello\xFF\x05World" #<Encoding:ASCII-8BIT>
  • このときに問題になるのが Encoding::ASCII_8BIT に対して UTF-8 などの文字列を結合しようとした場合にエラーになる
Post.new("H€llo", "Wôrld").serialize("somedata".b)
# => incompatible character encodings: ASCII-8BIT and UTF-8 (Encoding::CompatibilityError)
  • こういう問題を回避するためにバイト列単位で結合する String#byteconcat を追加する提案
class String
  def byteconcat(*strings)
    strings.map! do |s|
      if s.is_a?(String) && s.encoding != encoding
        s.dup.force_encoding(encoding)
      else
        s
      end
    end
    concat(*strings)
  end
end

Post = Struct.new(:title, :body) do
  def serialize(buf)
    buf.byteconcat(
      255, title.bytesize, title,
      255, body.bytesize, body,
    )
  end
end

Post.new("H€llo", "Wôrld").serialize("somedata".b)
# => "somedata\xFF\aH\xE2\x82\xACllo\xFF\x06W\xC3\xB4rld" #<Encoding:ASCII-8BIT>
  • これ系のデータってそもそも String で扱うべきなんですかねー
GitHubで編集を提案

Discussion