이중 값 텍스트 데이터를 이진수(비트 표현)로 변환하는 방법

이중 값 텍스트 데이터를 이진수(비트 표현)로 변환하는 방법

two (2)가능한 문자(및 새 줄)만 포함된 텍스트 파일이 있습니다 \n. 예:

ABBBAAAABBBBBABBABBBABBB

(크기 24 bytes)

이것을 어떻게 바이너리, 즉 비트 표현으로 변환하고 가능한 두 값을 각각 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

위의 내용은 한 번에 한 줄씩 입력을 읽습니다. 선이 의도한 대로 정확하게 표시되는지 확인하는 것은 사용자의 몫입니다.

편집하다:역연산:

#!/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 );

이번에는 한 번에 하나의 입력 바이트를 읽습니다.

편집 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하루 종일 나를 괴롭혔습니다. 고칠 수는 없었지만 뭔가 문제가 있다는 걸 알았습니다. 내 자신의 어리석음을 설명할 수 있다는 것은 매우 기뻤습니다. 특히 뭔가를 배웠기 때문입니다.

어쨌든 이는 가 아닌 모든 바이트를 제거하고 그에 따라 해석 [AB]한 다음 한 줄에 24바이트의 결과 스트림을 생성합니다. 한 번에 한 줄씩 읽고, 입력에 내용이 포함되어 있는지 확인하고, 포함되어 있으면 해당 숫자의 바이트 값을 표준 출력으로 인쇄합니다.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출력 의 경우 여기에 cut, , 을 expand추가 했습니다 od. 잠시 후에 설명하겠지만 또 하나 추가했습니다 . 배열을 하나씩 사용하는 dc다른 방법으로 스크립트를 한 줄씩 ?읽는 것을 포기했습니다. time - 이것은 ull 명령 스택을 표준 출력으로 dc인쇄하는 명령입니다 . f물론 스택 지향이기 때문에fdcdc후입 선출법애플리케이션 유형. 이는 f입력된 순서와 반대 순서로 ull-stack이 나타남을 의미합니다.

이것은 문제가 될 수 있지만 dc어쨌든 다른 것을 사용하고 o출력 기반을 다음으로 설정합니다.100000000가능한 한 간단하게 모든 0 패딩을 처리하십시오. 다른 사람의 글을 읽을 때후입 선출법흐름, 이 논리를 다시 적용하면 모든 것이 제자리에 놓이게 됩니다. 두 사람은 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.

...두 번째 쓰기의 결과 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개의 인코딩 비트로 채워지는 것을 쉽게 보장합니다. 프로세스가 반대가 되면 문자열은 -B두 개의 추가 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는 011100001111101101110111이 됩니다)

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로 바꿉니다.

우분투 16.04.7에서 테스트되었습니다.

관련 정보