packしないPerlの数値変換

16進文字列を整数値に

お約束。

my $num10 = hex("FF") #=255
my $num10 = hex("0xFF") #=255

8進文字列を整数値に

8進数…あまりお目にかからないですが、「0」から始まる数値文字列をoct()に渡すと処理してくれます。

my $num = oct("046"); #=38
#oct("0"."46")と考えるといいかも

2進数を整数値に

これもoct()が使えます。"0b"で始まる文字列を渡すと、2進数文字列として数値に変換されます。

my $num=oct("0b0010"); #=2
my $num2=oct("0b”.$str); #2進文字列がある場合

oct()は"0x"で始まる文字列も処理できます*1が、hex()があるのでそちらのほうが明示的だと思います。

oct関数で16進を作る、ってわかりにくいので。

数値から文字列にする

sprintfが使えます(と思っているのですがあまり見かけない*2 )。 0詰めもできます。ただし、通常のprintf同様、渡された文字列が文字数指定より長いと、0詰めに失敗します。

packと違って長さ無制限(?)です。(違うかも)

my $str_bin = sprintf ("%012b", 4) ; #="000000000100"
my $str_bin2 = sprintf ("%03b", 255) ; #="11111111" (3桁指定がうまくいかない例)

my $str_hex = sprintf ("%02x", 255) ; #="ff" (小文字)
my $str_hex2 = sprintf ("%02X", 255) ; #="FF" (大文字)

2進数文字列から16進数文字列へ

組み合わせ技。

my $str_hex=sprintf("%04x",oct("0b".$str_bin)); #4桁の16進数になる
#ただし、$num_binが大きすぎると4桁にならない

まとめ(?)

  • packはバイトオーダーやテンプレートの長さなど、慣れないとわからないことが多いです。文字列操作関数を使ったほうがわかりやすい時があるかもしれません。
    • spirntfのフォーマットもpackのテンプレートも覚える労力は同じ、かもしれませんが…。
  • かならず固定文字数で結果を得たいときにはpackが有利です。ただし、「桁数が切り捨てられてもいい」という場面は限られると思います。切り捨てられた桁数のために、複数回pack/unpackするなら、メンテナンス性などの点を考慮し*3、1度で書けるコードに変えることも検討していいと思います。
  • バイナリ処理であるpack/unpackのほうが速度面では有利かもしれません。ただ、短いスクリプトで1~3回使うだけのときや、繰り返し実行しないときには、そこまで気にする速度差は出ないと考えています。
  • とはいえ、packを使ったコードはよく見かけるので、使わなくても読むための知識は必要だと感じています。

*1: ただし、perlfuncのhex()解説によると、不正な文字列や空白文字で始まった時の扱いなどに差があるようです。

*2:%bはC言語と互換性がないせいかもしれません。ただし、多くの言語では%bが使えます。

*3:「プログラムの行数が長いほどバグが増える」というあるある法則。