質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.23%

バイナリデータを扱うpack / unpackで扱う値は何なのでしょうか

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 77

yoshiky

score 91

お世話になります。
rubyやphpにあるpack / unpack関数について質問です。

  • pack関数はテキスト文字をバイナリ文字に変換する関数、という認識で合ってますでしょうか。
    (「バイナリ文字列にパックする」という説明をよく見かけたのですが、パック=変換?)
    ※ちなみに「バイナリ文字」は「コンピュータが理解できる、テキストデータ以外のデータ」くらいの理解しかありません。。
  • 例えばrubyで下記のコードを実行した結果、下記の通りになったのですが変換後の値("\x01"や"\a")はどこから出てきたのでしょうか。ASCIIコードではないですよね。。
    また下記の[82, 117, 98, 121]をpackすると"Ruby"という文字になりますが、この[82, 117, 98, 121]は何の数字なのでしょうか。
[1] pry(main)> [1].pack('C*')
=> "\x01"
[2] pry(main)> [7].pack('C*')
=> "\a"
[3] pry(main)> [82, 117, 98, 121].pack('C*')
=> "Ruby"
  • unpackは「バイナリ(と文字列)を数値に変換する関数」という認識ですが、なんの数値に変換されるのでしょうか。
"a".unpack("C*")
=> [97]  # この 97 は何?
  • そもそもの前提知識が足りないために理解できないのですが、どういったキーワードで知識を仕入れたらよいでしょうか。 例)「文字コード」「バイナリとは」など。。

画像ファイルやExcelファイルなどテキストエディタで開けないようなファイルも、
コンピュータ上ではバイナリ形式(2進数)で表されるため、
プログラム上でそういったバイナリファイルを扱う際にpackを使うのかなー、といった程度の理解だったのですが、
前提知識がないため、いくら調べても分かりませんでした。。

できるだけ砕いて説明頂けると、または知識の仕入れ先を教えて頂けるとありがたいです。
よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

知識の仕入れ先としては、「コンピューター入門」のような書籍でしょうか。
「バイナリって、実際どう言うもので、どういう種類があるのか?」を念頭に読めば良いかと。

整数を1バイトバイナリに変換するのがpack("c")pack("C")で、
整数を4バイトバイナリに変換するのがpack("i")pack("I")で、
"0""1"という文字の連なりを2進数の文字列表現と見なして、(連なりの長さ÷8)バイトのバイナリに変換するのがpack("b*")pack("B*")とか、とか。

理解は半分以上間違っています。

pack関数はテキスト文字をバイナリ文字に変換する関数、という認識で合ってますでしょうか。

上記の通り、違います。

レシーバである[1]はASCIIコードの1で10進数で表現されており、結果の\x01はASCIIコードの1(10進数)を16進数で表現したもの、と理解しました。また、packの引数に指定するフォーマットをC*から別のものに変えたら、結果も16進数以外のものになる、と。

上記の通り、違います。

例えばrubyで下記のコードを実行した結果、下記の通りになったのですが変換後の値("\x01"や"\a")はどこから出てきたのでしょうか。

"\x01"は、1という値を持つ1バイトのRuby文字列表現。
"\a"は、7という値を持つ1バイトのRuby文字列表現。

また下記の[82, 117, 98, 121]をpackすると"Ruby"という文字になりますが、この[82, 117, 98, 121]は何の数字なのでしょうか。

それぞれ、R u b yの文字コードです。
文字と文字コードは、ord chrで変換できます。

p "R".ord #=> 82
p 117.chr #=> "u"

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/13 11:38

    ご回答ありがとうございます。「バイナリ」「文字コード」などのキーワードを中心に、コンピュータの基礎的な部分から学習しなおしてみます。

    「文字コード」といっても、エンコードがSJISなりUTF8によって、結果は変わってくると思っています。
    >"\x01"は、1という値を持つ1バイトのRuby文字列表現。
    ということですが、下記URLの表とは関係がないのでしょうか。16進数で表したら\x01 , 10進数なら1、といった理解です。(7の時\x07ではなく\aになる理由が分かりませんが。。)

    ASCII文字コード対応表 - National Instruments
    http://digital.ni.com/public.nsf/allkb/D831B5F2D5CA212E86257A21002055E6

    キャンセル

  • 2017/12/13 12:35 編集

    > エンコードがSJISなりUTF8によって、結果は変わってくると思っています。

    そうですね。回答したのはUS-ASCII互換のエンコーディングについてです。普通に使うエンコーティング大部分が該当します。US-ASCII互換でない例外は、UTF-16、UTF-32くらいでしょうか。


    > 下記URLの表とは関係がないのでしょうか。

    文字列の話なので、当然関係あります。その表のNULをRubyは "\x00"と表し、Aを"A"と表し、ESCを"\e"と表します。

    > 7の時\x07ではなく\aになる理由が分かりませんが

    直接には、Cの記法に倣ったためです。さらに理由としては、そのコードはBEL(ベル・・・端末の音を鳴らす)なので、「アラート(警告)」という意味でaが採用されています。主に警告のときにベルを鳴らすので。

    Rubyが各ASCII文字をどのように表示するかは、下記でわかります。
    p (0..127).to_a.pack("C*")

    キャンセル

  • 2017/12/13 11:57

    数値10は制御文字としてはLF(改行)で、16進数表記だと\x0Aで、(エスケープシーケンス+文字)表記だと\n
    数値7は制御文字としてはBEL(ベル)で、16進数表記だと\x07で、(エスケープシーケンス+文字)表記だと\a
    数値1は制御文字としてはSOH(ヘッダ開始)で、16進数表記だと\x01で、(エスケープシーケンス+文字)表記はない

    キャンセル

  • 2017/12/13 12:27

    お2人ともご解説ありがとうございました。
    一つ調べると3つくらい分からない用語が増えますが、調べるべき内容が分かりました!

    ちょっと勉強して出直してきます。

    キャンセル

  • 2017/12/13 13:22

    訂正です。
    US-ASCII互換でも、UTF-8だと、「1という値を持つ1バイト」のRubyでの文字列表現は"\u0001"のようになってしまいますね。値としては、US-ASCIIの"\x01"と同じなのですが。

    キャンセル

0

例えばrubyで下記のコードを実行した結果、下記の通りになったのですが変換後の値("\x01"や"\a")はどこから出てきたのでしょうか。ASCIIコードではないですよね。

いえ、ASCIIコードです。1や7をバイト列に変換して、さらにそれを文字として解釈したのが\x01なり\a\x07と同じ)です。

プログラム上でそういったバイナリファイルを扱う際にpackを使うのかなー、といった程度の理解だったのですが、
前提知識がないため、いくら調べても分かりませんでした。

packunpackを使う場面は、「バイナリで記録されたファイルを扱う」とか、「ネットワーク上を流れるバイナリデータを変換する」とか、通常はそのような前提があります。Rubyの世界だけで見ている場合は、なかなか使う機会はないと思いますし、ほぼお世話にはならないです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/12 16:51

    というより、何のためにpack/unpackを使うのかが気になります(Rubyだけでも、コードゴルフのような特殊な場面で使うこともなくはないですが)。

    キャンセル

  • 2017/12/12 17:39

    ご回答ありがとうございます。調べなおしたところ、確かに変換される値はASCII文字でした。
    [7].pack('C*')の結果出力された「\a」はASCIIコード表では「エスケープシーケンス」というもので、10進数で表すと7なのですね。 [1].pack('C*')の結果も16進数で返ってきたので、ASCII文字だと気づきませんでした。

    [自己解決の補足]
    [1].pack('C*') => \x01
    ※レシーバである[1]はASCIIコードの1で10進数で表現されており、結果の\x01はASCIIコードの1(10進数)を16進数で表現したもの、と理解しました。また、packの引数に指定するフォーマットをC*から別のものに変えたら、結果も16進数以外のものになる、と。

    >何のためにpack/unpackを使うのかが気になります
    使うことはないと思ってスルーしてたのですが、自前の暗号処理メソッドを作っていた知人が使っていたので、調べていた次第です。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.23%

関連した質問

  • 解決済

    Ruby標準入力から渡した値に関するinclude?メソッドの返却値

    以下のコードに関して、ソース上で値を渡した場合と、標準入力から同じ値を渡した場合の"include?"の返却値が異なります。どのような理由でこのような挙動になる理由を教えて下さい。

  • 解決済

    見栄え無視!とにかく軽くしたい

    rubyです。 0以上且つ9桁以下の整数値データを渡すと、加工して返す関数を作成しました。 行っている処理は ①送り値の数値を一桁ずつ調べていき、  1.その桁の数値が

  • 解決済

    rubyのプログラムへの入力に関しての質問です。

    質問です。 rubyでプログラムを作っているですが、入力時に改行付きの文字を送ると、改行前の文字しか認識しなくて困っています。 例えば 10 20 という風に入力する

  • 解決済

    配列の要素で最も文字数が少ないものを表示させたい

    ["アメリカ", "オーストラリア", "日本", "ロシア"] という配列があったとして、この中で最も文字数が少ないものだけを表示させたいのですが、その方法がわかりません。

  • 解決済

    Rubyのevalについて

    前提・実現したいこと 下記のようなコードにおいて、 数字が来た時はOKだが、文字列が来るとエラー。 逆に文字列が来る時はOKだが、数字がくるとエラーになる。 そこでeval

  • 解決済

    rubyのsplit関数のソースについて

    おはようございます rubyのsplitやchomp関数のソースがみたくて、rubyのgitをcloneしたのですが、それらしい部分がどこにもありませんでした。 かかれ

  • 解決済

    書いたコードのどこが間違っているのか分かりません

    num = gets.chomp.split("").map(&:to_i) while 1 flag = true (0..num.size-2).each do |i

  • 解決済

    pry内部でさらにpryできる理由

    偶然気づいたんですがpryを既に起動してる状態で更に入れ子構造でpryを起動できるようです。 この機能が実際どういう時に役立つのか全くわからないのですが、何か便利な時があるの

同じタグがついた質問を見る