Как читать и обрабатывать двоичные (с основанием 2) логические представления из файла

У меня есть файл, содержащий 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 не работает для двоичного. Итак, как бы я сделал это наиболее элегантно (или вообще, если уж на то пошло)?


person Community    schedule 14.04.2009    source источник
comment
Какие побитовые операции? Вам нужно проверять маски или всегда только отдельные биты?   -  person Torsten Marek    schedule 15.04.2009


Ответы (6)


Зачем их конвертировать и использовать битовые операции?

В 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 )
person S.Lott    schedule 14.04.2009
comment
Вы также можете преобразовать элементы в битах в логические значения с помощью: биты = [n!='0' для n в битах] Таким образом, вы можете просто сказать, если биты[2]:... - person FogleBird; 15.04.2009

В 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-битные числа.)

person Brian    schedule 14.04.2009

В C вы можете использовать "strtol(str, NULL, 2)" для преобразования, если вы уже делаете это в C.

Что-то вроде следующего будет работать:

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);
  ...
}

Вам нужно будет добавить обработку ошибок и т.д.

person Rick C. Petty    schedule 14.04.2009

«Простой» Perl one liner (замените 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++;
}
person Chas. Owens    schedule 14.04.2009

Расширение ответа Брайана:

# 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.

person user90855    schedule 14.04.2009

И, следуя давней традиции, вот версия для 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;
}

функция and() или(), xor() может отсутствовать в некоторых типах awk. Если это так, загрузите библиотеки для обработки битов. В сети плавают некоторые для awk. Или предоставить свой.

person GreenFox    schedule 19.08.2012