Как читать и обрабатывать двоичные (base-2) логические представления из файла - PullRequest
0 голосов
/ 15 апреля 2009

У меня есть файл, содержащий 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, выполнение побитовых операций в зависимости от пользовательского ввода и второго файла, преобразовать в базу-2, добавить ведущие нули и распечатать. Обычные консольные подсказки использовать bc не кажется элегантным, потому что у меня много строк в файле. То же самое относится и к dc.sed. И awk, похоже, не имеет эквивалентно маркировке ввода как двоичного (как в «echo $ ((2 # 101010))»), а также, трюк printf не работает для двоичного файла. Итак, как бы я это сделал наиболее элегантно (или вообще, если на то пошло)?

Ответы [ 6 ]

3 голосов
/ 15 апреля 2009

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

В 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 )
1 голос
/ 15 апреля 2009

В python вы можете преобразовать в двоичный файл, используя int, указав base 2. т.е.:

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

Для обратного преобразования, есть функция bin в python2.6 или 3, но не в python2.5, поэтому вам нужно реализовать ее самостоятельно (или использовать что-то вроде ниже):

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

>>> bin(447, 9)
110111111

(Ширина - это количество цифр для заполнения - ваши примеры, похоже, используют 9-битные числа.)

0 голосов
/ 19 августа 2012

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

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

0 голосов
/ 15 апреля 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 module для получения дополнительной информации о модуле csv.

0 голосов
/ 15 апреля 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++;
}
0 голосов
/ 15 апреля 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);
  ...
}

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

...