二重値テキストデータをバイナリ(ビット表現)に変換する方法

二重値テキストデータをバイナリ(ビット表現)に変換する方法

two (2)可能な文字(および新しい行)のみを含むテキストファイルがあります\n。例:

ABBBAAAABBBBBABBABBBABBB

(サイズ24 bytes

これをどのようにバイナリ、つまりビット表現に変換し、2つの可能な値をそれぞれまたは0に割り当てますか1

生成されたバイナリファイル(0=A、、1=B):

011100001111101101110111     # 24 bits - not 24 ASCII characters

16進結果ファイル:

70FB77                       # 3 bytes - not 6 ASCII characters

私はコマンドラインソリューション(たぶん、、、、、、、、、dd)に最も興味があります。また、逆の場合:原稿を元に戻す方法は?xxdodtrprintfbc

答え1

もう一つのパール:

perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0\1/; $_ = pack "B*", $_'

証明する:

$ echo ABBBAAAABBBBBABBABBBABBB | \
    perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0\1/; $_ = pack "B*", $_' | \
    od -tx1
0000000 70 fb 77
0000003

上記は、一度に1行ずつ入力を読みます。線が意図したとおりに正確に表示されることを確認するのはユーザーの役割です。

編集する:逆演算:

#!/usr/bin/env perl

binmode \*STDIN;

while ( defined ( $_ = getc ) ) {
    $_ = unpack "B*";
    tr/01/AB/;
    print;
    print "\n" if ( not ++$cnt % 3 );
}
print "\n" if ( $cnt % 3 );

今回は一度に1つの入力バイトを読み込みます。

編集2:より簡単なリバース操作:

perl -pe 'BEGIN { $/ = \3; $\ = "\n"; binmode \*STDIN } $_ = unpack "B*"; tr/01/AB/'

上記は一度に3バイトを読みますSTDIN(ただし、EOFシーケンスの途中で受信することは致命的な問題ではありません)。

答え2

{   printf '2i[q]sq[?z0=qPl?x]s?l?x'
    tr -dc AB | tr AB 01 | fold -b24
}   <infile   | dc

@lcd047は、次のような声明を使って、以前の混乱状態を見事に解決しました。

の出力により混乱しているようですod。バイトを表示するために使用されますod -tx1od -xリトルエンディアンシステムで単語を読み、バイトを交換します。上記のスワップに詳しく従わなかったのですが、初期バージョンが正確でエンディアンをまったく台無しにする必要はないと思います。ただ使用してくださいod -tx1。使用しないでくださいod -x

今こんな感じです。たくさんより良い - 以前のニーズはdd conv=swab一日中私を悩ませています。修正することはできませんでしたが、何か問題があることがわかりました。私自身の愚かさを説明できることはとても嬉しかったです。特に何かを学んだからです。

とにかく、それ以外のすべてのバイトを削除し、それに応じて解釈し、1行[AB]に24バイトの結果ストリームを生成します。一度に1行ずつ読み込み、入力に内容が含まれていることを確認し、含まれている場合はその数値のバイト値を標準出力に出力します。tr[01]folddc ?P

からman dc

  • P

    • スタックの上部にある値をポップします。文字列の場合は、末尾の改行なしで単に印刷されます。それ以外の場合は数値で、絶対値の整数部分は次のように印刷されます。「によると(UCHAR_MAX+1)」バイトストリーム。
  • i

    • スタックの上部に値をポップし、それを使用して入力基準を設定します。

一部のシェルの自動化

以下は、上記の内容に基づいて私が作成したシェル関数で、双方向で実行できます。

ABdc()( HOME=/dev/null  A='[fc[fc]]sp[100000000o]p2o[fc]' B=2i
        case    $1      in
        (-B) {  echo "$B"; tr AB 01      | paste -dP - ~      ; }| dc;;
        (-A) {  echo "$A"; od -vAn -tu1  | paste -dlpx - ~ ~ ~; }| dc|
         dc  |  paste - - - ~            | expand -t10,20,30     |
                cut -c2-9,12-19,22-29    | tr ' 01' AAB         ;;
        (*)     set '' "$1";: ${1:?Invalid opt: "'$2'"}         ;;
        esac
)

これは翻訳されますABABABAパディングバイトを使用すると、-B次のようにできます。

ABdc -B <infile

ただし、すべての入力を24に変換します。ABABABAバイトあたりのビットでエンコードされた文字列 - 質問に示されているのと同じ形式 - w / -B

seq 5 | ABdc -A | tee /dev/fd/2 | ABdc -B

AABBAAABAAAABABAAABBAABA
AAAABABAAABBAABBAAAABABA
AABBABAAAAAABABAAABBABAB
AAAABABAAAAAAAAAAAAAAAAA
1
2
3
4
5

-A出力の場合ここに、、cutexpand追加しましたod。しばらくして説明しますが、もう1つ追加しました。配列を1つずつ使用するdc別の方法でスクリプトを1行ずつ?読み込むことを放棄しました。 time - これはullコマンドスタックを標準出力にdc出力するコマンドです。fもちろんスタック志向だからfdcdc後入選出法アプリケーションタイプ。これは、f入力された順序とは逆の順序でull-stackが表示されることを意味します。

これは問題かもしれませんが、dcとにかく別のものを使用し、o出力ベースを次のように設定します。100000000できるだけ簡単にすべてのゼロパディングを処理します。他人の記事を読むとき後入選出法フロー、このロジックを再適用すると、すべてが所定の位置に置かれます。二人はdc次のように一緒に働きます。

{   echo '[fc[fc]]sp[100000000o]p2o[fc]'
    echo some data | 
    od -An -tu1        ###arbitrary input to unsigned decimal ints
    echo lpx           ###load macro stored in p and execute
} | tee /dev/fd/2  |   ###just using tee to show stream stages
dc| tee /dev/fd/2  |dc 

...最初のストリームtee...

[fc[fc]]sp[100000000o]pc2o[fc]            ###dc's init cmd from 1st echo
 115 111 109 101  32 100  97 116  97  10  ###od's output
lpx                                       ###load p; execute

...毎秒teedcからdc...

100000000o                             ###first set output radix
1010                                   ###bin/rev vs of od's out
1100001                                ###dc #2 reads it in, revs and pads it 
1110100                                
1100001
1100100
100000
1100101
1101101
1101111                                ###this whole process is repeated
1110011                                ###once per od output line, so
fc                                     ###each worked array is 16 bytes.

...2番目の書き込みの結果dcは...

 01110011
 01101111
 01101101
 01100101
 00100000
 01100100
 01100001
 01110100
 01100001
 00001010

そこで、関数はpasteそれを<tabs>に置きます...

 01110011    01101111    01101101
 01100101    00100000    01100100
 01100001    01110100    01100001
 00001010

... expands <tabs>を10列の区切りスペースに変換...

 01110011  01101111  01101101
 01100101  00100000  01100100
 01100001  01110100  01100001
 00001010

...cutバイトを除くすべてが消えた。2-9,12-19,22-29...

011100110110111101101101
011001010010000001100100
011000010111010001100001
00001010

...そしてtr<スペース>と0を次のように解釈します。AそしてそれらB...

ABBBAABBABBABBBBABBABBAB
ABBAABABAABAAAAAABBAABAA
ABBAAAABABBBABAAABBAAAAB
AAAABABAAAAAAAAAAAAAAAAA

最後の行で私が追加した主な動機を見ることができますexpand。これは非常に軽いフィルタで、作成されたすべてのシーケンス(最後のシーケンスまでを含む)が24のエンコードビットで埋められることを容易に保証します。プロセスが逆になると、文字列は-B2つの追加のNULと共にyte値に復号されます。

ABdc -B <<\IN | od -tc
ABBBAABBABBABBBBABBABBAB
ABBAABABAABAAAAAABBAABAA
ABBAAAABABBBABAAABBAAAAB
AAAABABAAAAAAAAAAAAAAAAA
IN

...ご覧のように...

0000000   s   o   m   e       d   a   t   a  \n  \0  \0
0000014

実データ

遊びながらシンプルで実用的な流れを試してみました。段階的な報告のために、この複雑なパイプラインを構築しました。

{                            ###dunno why, but I often use man man
    (                        ###as a test input source
        {   man man       |  ###streamed to tee
            tee /dev/fd/3 |  ###branched to stdout
            wc -c >&2        ###and to count source bytes
        }   3>&1          |  ###the branch to stdout is here
        ABdc -A           |  ###converted to ABABABA
        tee /dev/fd/3     |  ###branched again
        ABdc -B              ###converted back to bytes
        times >&2            ###the process is timed
    ) | wc -c >&2            ###ABdc -B's output is counted
} 3>&1| wc -c                ###and so is the output of ABdc -A

しかし、ここではパフォーマンスを比較する良い根拠はありません。私が言うことができるのは、私がこのテストを強制することになったということだけです。(たぶん無邪気なことかもしれません)これをするほど印象的です...

man man | ABdc -A | ABdc -B

man...フィルタリングされていないコマンドと同じ識別可能な速度で端末画面に出力を描画します。テスト結果は...

37595                       ###source byte count
0m0.000000s 0m0.000000s     ###shell processor time nil
0m0.720000s 0m0.250000s     ###shell children's total user, system time
37596                       ###ABdc -B output byte count
313300                      ###ABdc -A output byte count

予備テスト

残りは実際に機能するより簡単な概念証明です。

printf %s ABBBAAAABBBBBABBABBBABBB|
tee - - - - - - - -|
tee - - - - - - - - - - - - - - - |
{   printf '2i[q]sq[?z0=qPl?x]s?l?x'
    tr -dc AB | tr AB 01 | fold -b24
} | dc        | od -tx1
0000000 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70
0000020 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB
0000040 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77
0000060 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70
0000100 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB
0000120 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77
0000140 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70
0000160 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB
0000200 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77
0000220 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70
0000240 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB
0000260 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77
0000300 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70
0000320 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB
0000340 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77
0000360 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70
0000400 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB
0000420 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77
0000440 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70
0000460 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB
0000500 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77
0000520 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70
0000540 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB
0000560 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77
0000600 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70
0000620 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB
0000640 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77 70 FB 77
0000660

答え3

真珠:

my $len = 24;
my $str = "ABBBAAAABBBBBABBABBBABBB\n";
$str =~ s/\s//g;
(my $bin = $str) =~ y/AB/01/;
my $val = oct("0b".$bin);
printf "%s -> %s -> %X\n", $str, $bin, $val;

my ($filename, $fh) = ("temp.out");

# write the file
open $fh, '>', $filename;
print $fh pack("N", $val);      # this actually writes 4 bytes
close $fh;

# now read it, and convert back to a string:
open $fh, '<', $filename;
read $fh, my $data, 4;
close $fh;

my $new_val = unpack "N", $data;
my $new_bin = substr unpack("B32", $data), -$len;
(my $new_str = $new_bin) =~ y/01/AB/;

printf "%X -> %s -> %s\n", $new_val, $new_bin, $new_str;
ABBBAAAABBBBBABBABBBABBB -> 011100001111101101110111 -> 70FB77
70FB77 -> 011100001111101101110111 -> ABBBAAAABBBBBABBABBBABBB

lcd047の完璧な答えのおかげで、私の答えは次のようになります。

my $str = "ABBBAAAABBBBBABBABBBABBB\n";
$str =~ s/\s//g;
(my $bin = $str) =~ y/AB/01/;
printf "%s -> %s\n", $str, $bin;

my ($filename, $fh) = ("temp.out");

# write the file
open $fh, '>', $filename;
print $fh pack("B*", $bin);
close $fh;

my $size = -s $filename;
print $size, "\n";

# now read it, and convert back to a string:
open $fh, '<', $filename;
read $fh, my $data, 1024;
close $fh;

my $new_bin = unpack("B*", $data);
(my $new_str = $new_bin) =~ y/01/AB/;

printf "%s -> %s\n", $new_bin, $new_str;
ABBBAAAABBBBBABBABBBABBB -> 011100001111101101110111
3
011100001111101101110111 -> ABBBAAAABBBBBABBABBBABBB

答え4

テキストファイルの文字を置き換える:

sed -i 's/A/0/g' file.in
sed -i 's/B/1/g' file.in

改行文字を表すために\ nを使用している場合は、改行文字で置き換えてください。

sed 's/\\n/\'$'\n''/g' file.in

(ABBBAAAABBBBBABBABBBABBBは0111000011111101101110111になります)

file.inのascii(文字列)をバイナリファイルに書き込む(現状のまま)バイナリデータとして扱います。

data=$(cat file.in)

# replace file
echo $(printf '%x\n' "$((2#$data))") | xxd -r -p > file.out
# or write to existing file without truncating
echo $(printf '%x\n' "$((2#$data))") | xxd -r -p - file.out

(3バイト)バイナリファイルを読み取ると、次の16進コードが提供されます。

hd file.out
70fb77

デコード(逆方向)するには、hdまたはxxdを使用してバイナリファイルを読み取り、16進コードをバイナリに変換し、0と1をAとBに置き換えます。

Ubuntu 16.04.7でテストされました。

関連情報