
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
)に最も興味があります。また、逆の場合:原稿を元に戻す方法は?xxd
od
tr
printf
bc
答え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 -tx1
。od -x
リトルエンディアンシステムで単語を読み、バイトを交換します。上記のスワップに詳しく従わなかったのですが、初期バージョンが正確でエンディアンをまったく台無しにする必要はないと思います。ただ使用してくださいod -tx1
。使用しないでくださいod -x
。
今こんな感じです。たくさんより良い - 以前のニーズはdd conv=swab
一日中私を悩ませています。修正することはできませんでしたが、何か問題があることがわかりました。私自身の愚かさを説明できることはとても嬉しかったです。特に何かを学んだからです。
とにかく、それ以外のすべてのバイトを削除し、それに応じて解釈し、1行[AB]
に24バイトの結果ストリームを生成します。一度に1行ずつ読み込み、入力に内容が含まれていることを確認し、含まれている場合はその数値のバイト値を標準出力に出力します。tr
[01]
fold
dc
?
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
出力の場合ここに、、cut
をexpand
追加しましたod
。しばらくして説明しますが、もう1つ追加しました。配列を1つずつ使用するdc
別の方法でスクリプトを1行ずつ?
読み込むことを放棄しました。 time - これはullコマンドスタックを標準出力にdc
出力するコマンドです。f
もちろんスタック志向だからf
dc
dc
後入選出法アプリケーションタイプ。これは、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
...毎秒tee
、dc
から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
... expand
s <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のエンコードビットで埋められることを容易に保証します。プロセスが逆になると、文字列は-B
2つの追加の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でテストされました。