💨
[bugs.ruby][Feature #20196] バイナリデータを定義するリテラルを追加する提案
[Feature #20196] Proposal: Binary data literal
- 以下のようなバイナリデータを定義するリテラル(%記法?)を追加する提案
%b[
89504e470d0a1a0a # PNG header
0000000d # Length = 13 bytes
49484452 # IHDR chunk
00000060 # Width = 96px
00000060 # Height = 96px
08 06 # 8bpp RGBA
00 00 00 # deflate / no filter / non-interlaced
]
# => "\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00`\x00\x00\x00`\b\x06\x00\x00\x00"
- 仕様は以下のような感じ
- 16進文字列(上位ニブルが先)
- 他の%記法と同じルール
-
%b[]
はString
を返し%B[]
はIO::Buffer
を返す - 空白文字は無視される
- コメントを書くことができる
- エンコーディングは
Encoding::BINARY
になる - 結果の文字列は
frozen
になる -
a-f
はA-F
ともかける
- 普段 Ruby のコードを書いている時にバイナリデータを直接コードを書くことはないんですが、あると使う場面があったりするんですかねー
- 他には以下のような『空白文字を取り除きコメントをサポートする%記法を新しく追加する』みたいな話もあります
%c[
The quick brown # comment
fox jumped over # another comment
the lazy dog. # a third comment
] # => "The quick brown fox jumped over the lazy dog."
# 今回のケースはこういう風にかける
[%c[
000102 # foo
030405 # bar
].delete(' ')].pack("H*").freeze
- これだと汎用性があるのでより利用できそうな場面はありそうですね
- また、以下のように実装することもできるとコメントに書いてありますね
module Kernel
def Binary(string, exception: true)
hex = string.b
hex.gsub!(/#[^#]*$\R*/, '')
hex.gsub!(/"[^"]*"/) do |quotes|
quotes[1..-2].unpack1('H*')
end
hex.delete!("\s\t")
if hex.match?(/\H/)
return unless exception
invalid_chars = hex.scan(/\H/).to_set.join
raise ArgumentError,
"invalid non-hex chars for Binary(): #{invalid_chars.inspect}"
end
[hex].pack('H*').freeze
end
end
string = <<-BINARY
89 "PNG" 0d0a1a0a # PNG header
0000000d # Length = 13 bytes
"IHDR" # IHDR chunk
00000060 # Width = 96px
00000060 # Height = 96px
08 06 # 8bpp RGBA
00 00 00 # deflate / no filter / non-interlaced}
BINARY
binary = Binary(string)
pp string: binary, encoding: binary.encoding, frozen: binary.frozen?
# => {:string=>"\x89PNG\r\n" + "\x1A\n" + "\x00\x00\x00\rIHDR\x00\x00\x00`\x00\x00\x00`\b\x06\x00\x00\x00",
# :encoding=>#<Encoding:ASCII-8BIT>,
# :frozen=>true}
- これはこれで面白い
Discussion