0

我有一个包含 800 行的文件,例如:

id       binary-coded-info
---------------------------
4657     001001101
4789     110111111
etc.

其中每个 0 或 1 代表某些特征的存在。我想读取这个文件并对二进制编码信息执行几个按位逻辑操作(这些操作取决于用户输入和来自具有 3000 行的第二个文件的信息)。然后,这些重新计算的二进制编码信息应写入文件(带有尾随零,例如

4657     000110011
4789     110110000
etc.

如果不编写自己的基本转换例程,我应该如何做到这一点?我对任何东西都开放,包括我不知道的语言,比如 python、perl 等。它应该可以在不编译的情况下工作。

到目前为止,我尝试按照自己的方式编写脚本、awk 和 sed。这将意味着(我认为):批量读取为 base-2,转换为 base-10,根据用户输入和第二个文件进行按位运算,转换为 base-2,添加前导零并打印。使用 bc 的常用控制台提示似乎并不优雅,因为我在一个文件中有很多行。dc.sed 也是如此。并且 awk 似乎没有等同于将输入标记为二进制(如 "echo $((2#101010))" ),而且 printf 技巧不适用于二进制。那么,我将如何最优雅地做到这一点(或者,就此而言)?

4

6 回答 6

3

为什么要转换它们并使用位操作?

在 Python 中,您可以将所有这些作为字符串执行。

for line in myFile:
    key, value = line.split()
    bits = list(value)
    # bits will be a list of 1-char strings ['1','0','1',...]
    # ... do stuff to bits ...
    print key, "".join( value )
于 2009-04-14T21:10:10.340 回答
1

在 python 中,您可以使用 int 转换为二进制,指定基数 2。即:

>>> int('110111111',2)
447

要转换回来,在 python2.6 或 3 中有一个bin函数,但在 python2.5 中没有,所以你需要自己实现它(或使用类似下面的东西):

def bin(x, width):
    return ''.join(str((x>>i)&1) for i in xrange(width))[::-1]

>>> bin(447, 9)
110111111

(宽度是要填充的位数 - 您的示例似乎使用 9 位数字。)

于 2009-04-14T22:33:40.140 回答
0

扩展布赖恩的回答:

# Get rid of the '----' line for simplicity
data_file = '''id       binary-coded-info
4657     001001101
4789     110111111
'''
import cStringIO
import csv, sys
data = [] # A list for the row dictionaries (we could just as easily have used the regular reader method)
# Read in the file using the csv module
# Each row will be a dictionary with keys corresponding to the first row
reader = csv.DictReader(cStringIO.StringIO(data_file), delimiter=' ', skipinitialspace = True)
try:
    for row in reader:
        data.append(row) # Add the row dictionary to the data list
except csv.Error, e:
    sys.exit('file %s, line %d: %s' % (filename, reader.line_num, e))
# Do something with the bits
first = int(data[0]['binary-coded-info'],2) # First bit string
assert(first & int('00001101',2) == int('1101',2)) # Bitwise AND
assert(first | int('00001101',2) == int('1001101',2)) # Bitwise OR
assert(first ^ int('00001101',2) == int('1000000',2)) # Bitwise XOR
assert(~first == int('110110010',2)) # Binary Ones Complement
assert(first << 2 == int('100110100',2)) # Binary Left Shift
assert(first >> 2 == int('000010011',2)) # Binary Right Shift

有关更多信息,请参阅有关表达式的 python 文档,有关csv 模块的更多信息,请参阅 csv 模块。

于 2009-04-14T23:34:27.780 回答
0

“简单”的 Perl 一个衬里(用你的标志替换 foo bar baz quux

perl -le '@f=qw/foo bar baz quux/;$_&&print($f[$i]),$i++for split//, shift' 1011

这是一个可读的 Perl 版本:

#!/usr/bin/perl

use strict;
use warnings;

#flags that can be turned on and off, the first 
#flag is turned on/off by the left-most bit
my @flags = (
    "flag one",
    "flag two",
    "flag three",
    "flag four",
    "flag five",
    "flag six",
    "flag seven",
    "flag eight",
);

#turn the command line argument into individual
#ones and zeros
my @bits = split //, shift; 

#loop through the bits printing the flag that
#goes with the bit if it is 1
my $i = 0;
for my $bit (@bits) {
    if ($bit) {
        print "$flags[$i]\n";
    }
    $i++;
}
于 2009-04-14T22:34:54.617 回答
0

在 C 中,如果您已经在 C 中执行此操作,则可以使用“strtol(str, NULL, 2)”进行转换。

像下面这样的东西会起作用:

FILE* f = fopen("myfile.txt", "r");
char line[1024];
while ((line = fgets(line, sizeof(line), f))
{
  char* p;
  long column1 = strtol(line, &p, 10);
  long column2 = strtol(p, &p, 2);
  ...
}

您需要添加错误处理等。

于 2009-04-14T21:05:30.197 回答
0

遵循悠久的传统,这里有一个 awk 版本 :-)
最后检查 gawk 4.0.1
应该也适用于其他 awk。

{
      var = _int("00010101",2);
      print _bin( or( var ,  _int("00101001",2) ) , 8 ) 
      print _bin( and( var , _int("10110111",2) ) , 8 ) 
      print _bin( xor( var ,var ) , 8 );
}    

# convert var to d-ht base. Specify 16 for hex, 8 for oct, and such. Up to base 36, for fruther base, provide X. if d<=36, and wish to use custom X, provide 1 for i.
function _obase( v , d , X , i, this , r ){
  if(d<=9){r="";while(v){r=v%d""r;v=int(v/d)};return r;}
  if(d<=36&&!i){for(i=0;i<=9;i++)X[i]=""i;for(;i<d;i++)X[i]=sprintf("%c",55+i);}
  r="";while(v){r=X[v%d]""r;v=int(v/d)};return r;
}
function _pad(d, p, w, this ,r){
  r=""d;while(length(r)<w)r=p""r;return r;
}
function _bin( v , w , this ){
  return _pad(_obase(v,2),"0",w);
}
# convert string to var, using d as base. for base>36, specify X. if wish to use custom X, provide 1 to i
function _int( s , d , X , i , this , k , r ){
  r=0;k=length(s);if(d<=9){for(i=1;i<=k;i++){r*=d;r=r+int(substr(s,i,1));}return r;}
  if(d<=36&&!i){for(i=0;i<=9;i++)X[""i]=i;for(;i<d;i++)X[sprintf("%c",55+i)]=i;}
    for(i=1;i<=k;i++){r*=d;r=r+X[substr(s,i,1)];}eturn r;
}

某些类型的 awk 可能缺少函数 and()、or()、xor()。如果是这样,请加载位操作库。网上有一些for awk。或者提供你自己的。

于 2012-08-19T13:36:10.110 回答