AWK将十进制转换为二进制

3
我想使用AWK将文件中的十进制数字列表转换为二进制,但似乎没有内置的方法。示例文件如下:
134218506
134218250
134217984
1610612736
16384
33554432
7个回答

8

以下是一种awk的方法,已经转化为函数方便使用:

awk '
function d2b(d,  b) {
      while(d) {
          b=d%2b
          d=int(d/2)
      }
      return(b)
}
{
    print d2b($0)
}' file

前三个记录的输出:

1000000000000000001100001010
1000000000000000001000001010
1000000000000000000100000000

1
谢谢@RavinderSingh13。我刚拿到了我的黄金 AWK 标签。 - James Brown
1
太棒了,恭喜。您真的值得这个称号,向您致敬。 - RavinderSingh13

2

以下是一种方法,首先将十进制转换为十六进制,然后将每个十六进制字符转换为其二进制等效物:

$ cat dec2bin.awk
BEGIN {
    h2b["0"] = "0000";  h2b["8"] = "1000"
    h2b["1"] = "0001";  h2b["9"] = "1001"
    h2b["2"] = "0010";  h2b["a"] = "1010"
    h2b["3"] = "0011";  h2b["b"] = "1011"
    h2b["4"] = "0100";  h2b["c"] = "1100"
    h2b["5"] = "0101";  h2b["d"] = "1101"
    h2b["6"] = "0110";  h2b["e"] = "1110"
    h2b["7"] = "0111";  h2b["f"] = "1111"
}

{ print dec2bin($0) }

function hex2bin(hex,   n,i,bin) {
    n = length(hex)
    for (i=1; i<=n; i++) {
        bin = bin h2b[substr(hex,i,1)]
    }
    sub(/^0+/,"",bin)
    return bin
}

function dec2bin(dec,   hex, bin) {
    hex = sprintf("%x\n", dec)
    bin = hex2bin(hex)
    return bin
}

$ awk -f dec2bin.awk file
1000000000000000001100001010
1000000000000000001000001010
1000000000000000000100000000
1100000000000000000000000000000
100000000000000
10000000000000000000000000


1

你可以尝试使用Perl的一行命令

$ cat hamdani.txt
134218506
134218250
134217984
134217984
1610612736
16384
33554432


$  perl -nle ' printf("%b\n",$_) ' hamdani.txt
1000000000000000001100001010
1000000000000000001000001010
1000000000000000000100000000
1000000000000000000100000000
1100000000000000000000000000000
100000000000000
10000000000000000000000000

$

1
你可以尝试使用dc:
# -f infile : Use infile for data
# after -e , it is there are the dc command
dc -f infile -e '
  z          # number of values
  sa         # keep in register a
  2
  o          # set the output radix to 2 : binary
  [
    Sb       # keep all the value of infile in the register b  
             # ( b is use here as a stack)
    z
    0 <M     # until there is no more value
  ] sM       # define macro M in [ and ]
  lMx        # execute macro M to populate stack b
  [ 
    Lb       # get all values one at a time from stack b
    p        # print this value in binary
    la       # get the number of value
    1
    -        # decremente it
    d        # duplicate
    sa       # keep one in register a
    0<N      # the other is use here
  ]sN        # define macro N
  lNx'       # execute macro N to print each values in binary

ctac_.. 我看到你很多答案使用了 dc 和像一些随机字符串生成器的选项 :-),你是在哪里查找答案还是已经练习过了?我一直很好奇!不管怎样,加加。 - stack0114106
@stack0114106 不太确定我是否理解你的意思(就像G-Man认为所有人都可以轻松地解释一样:))。关于dc的文档不是很多。每次我使用它,我都必须使用man dc。它几乎是汇编语言,因此是二进制的。我在答案中为您添加了解释。 - ctac_
为什么要回答一个关于awk的问题,但是却提供一个不使用awk的解决方案呢? - bfontaine

0
# gawk binary number functions
# RPC 09OCT2022

# convert an 8 bit binary number to an integer
function bin_to_n(i)
{
    n = 0;
    #printf(">> %s:", i);
    for (k = 1; k < 9; k++) {
        n = n * 2;
        b = substr(i, k, 1);
        if (b == "1") {
            n = n + 1;
        }
    }
    return (n);
}

# convert a number to a binary number
function dectobin(n)
{
    printf("dectobin: n in %d ",n);
    binstring = "0b"; # some c compilers allow 0bXXXXXXXX format numbers
    bn = 128;
    for(k=0;k<8;k++) {
        if (n >= bn) {
            binstring = binstring "1";
            n = n - bn;
        } else {
            binstring = binstring "0"
        }
    printf(" bn %d",bn);
    bn = bn / 2;
    }
    return binstring;

}

BEGIN {
    FS = " ";

    # gawk (I think) has no atoi() funciton or equiv. So a table of all 
    # chars (well 256 ascii) can be used with the index function to get 
    # round this
    for (i = 0; i < 255; i++) {
       table = sprintf("%s%c", table, i);
    }
}

{
    # assume on stdin a buffer of 8 bit binary numbers "01000001 01000010" is AB etc
    for (i = 1; i <= NF; i++)
        printf("bin-num#%d: %x --> %c\n", i, bin_to_n($i), bin_to_n($i));

    s = "ABC123string to test";
    for (i = 0; i < length(s); i++) {
    nn = index(table, substr(s,i+1,1))-1;
    printf("substr  :%s:%x:",ss,nn);
        printf(" :%d: %s\n", i, dectobin(nn));
    }
}

0

除了别人已经提到的内容,这个函数还有一个快捷方式,可以用于非负整数幂次为2的情况。

—-(因为它们总是有二进制模式 / ^ [1] [0] * $ /

版本1:以3位一组的方式处理,而不是逐位处理:

   {m,g}awk '
   BEGIN {
 1     CONVFMT="%.250g"
 1     _^=OFMT="%.25g"
   }
   ($++NF=________v1($_))^!_
    
   function ________v1(__,___,_,____,_____)
   {
 6     if (+__==(_+=_^=____="")^(___=log(__)/log(_))) { # 2
 2        return \
               ___<=_^_^_ \
               ? (_+_*_*_)^___ \
               : sprintf("%.f%0*.f",--_,___,--_)
      }
 4     ___=(!_!_!_!!_) (_^((_____=_*_*_)+_)-_^_^_+(++_))
 4     gsub("..", "&0&1", ___)
41     while(__) {
41        ____ = substr(___,
                        __%_____*_+(__=int(__/_____))^!_,_)____
      }
 4     return substr(__=____, index(__, _^(! _)))
   }'

版本 2:首先使用 sprintf() 将数字转换为八进制,然后再映射到二进制。
  function ________v2(__,___,_,____,_____)
   {
 6     if (+__==(_+=_^=____="")^(___=log(__)/log(_))) { # 2
 2        return \ 
               ___<=_^_^_ \
               ? (_+_*_*_)^___ \
               : sprintf("%.f%0*.f",--_,___,--_)
      }
 4     ___=(!_!_!_!!_) (_^((_____=_*_*_)+_)-_^_^_+(++_))
 4     gsub("..", "&0&1", ___)
 4     _____=___
 4     __=sprintf("%o%.*o", int(__/(___=++_^(_*--_+_))),
                                       _*_+!!_, __%___)
 4     sub("^[0]+", "", __)
41     for (___=length(__); ___; ___--) {

41        ____ = substr(_____, substr(__,
                        ___,!!_)*_ + !!_,_)____
      }
 4     return substr(____, index(____,!!_))
   }

|

134218506 1000000000000000001100001010
134218250 1000000000000000001000001010
134217984 1000000000000000000100000000
1610612736 1100000000000000000000000000000
16384 100000000000000
33554432 10000000000000000000000000

版本 3:通过使用缓存数组和每轮处理 8 位,可以实现相当快的速度(在 mawk2 上达到 29.5 MB/s 吞吐量)。
  • 输出以至少 8 个二进制位宽度的零填充

.

  {m,g,n}awk '
 1  function ________(_______,_, __,____,______)
   {
 1     split(_=__=____=______="", _______, _)
 2     for (_^=_<_; -_<=+_; _--) {
 4        for (__^=_<_; -__<=+__; __--) {
 8             for (____^=_<_; -____<=+____; ____--) {
16                 for (______^=_<_; -______<=+______; ______--) {
16                     _______[_+_+_+_+_+_+_+_+__+__+\
                               __+__+____+____+______]=\
                                      (_)__ (____)______
               }
            }
         }
      }
 1     return _^(_<_)
   }
   BEGIN {

 1     CONVFMT = "%." ((_+=(_^=_<_)+(_+=_))*_)(!_)"g"
 1        OFMT = "%." (_*_) "g"
 1     _ = ________(_____)
   }
   ($++NF=___($_))^!_ 

   function ___(__,____,_,______)
   {
 6     if ((__=int(__))<(______=\
                (_*=_+=_+=_^=____="")*_)) {

           return _____[int(__/_)]_____[__%_]
       }
16     do { ____=_____[int(__/_)%_]_____[__%_]____

       } while (______<=(__=int(__/______)))

 6     return int(_____[int(__/_)%_]\
                  _____[   (__)  %_])____
   }

-1

你不应该使用awk,而是用bc

$ bc <<EOF
  ibase=10
  obase=2
  $(cat file)
  EOF

或者

bc <<< $(awk 'BEGIN{ print "ibase=10; obase=2"}1' file)

我给你的回答点了踩,因为这个问题是关于awk的,所以说“你不应该使用awk”并不是一个可接受的答案。 - bfontaine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接