Как заменить смежные байты в строку шестнадцатеричных байтов (с регулярными выражениями или без них) - PullRequest
1 голос
/ 19 января 2010

Учитывая строку (или любую строку длины с четным числом пар слов): "12345678"

Как бы я поменял соседние "слова"?

Результат, который я хочу получить "34127856"

Кроме того, когда это будет сделано, мне нужно поменяться местами. Результат, который я хочу получить: "78563412"

Ответы [ 6 ]

4 голосов
/ 19 января 2010

Подход регулярного выражения:

import re
twopairs = re.compile(r'(..)(..)')
stringwithswappedwords = twopairs.sub(r'\2\1', basestring)
twoquads = re.compile(r'(....)(....)')
stringwithswappedlongs = twoquads.sub(r'\2\1', stringwithswappedwords)

Редактировать : Тем не менее, это определенно не самый быстрый подход в Python - вот как можно узнать о таких вещах: во-первых, запишите все «конкурирующие» подходы в модуль, здесь я называю его 'swa.py' ...:

import re

twopairs = re.compile(r'(..)(..)')
twoquads = re.compile(r'(....)(....)')

def withre(basestring, twopairs=twopairs, twoquads=twoquads):
  stringwithswappedwords = twopairs.sub(r'\2\1', basestring)
  return twoquads.sub(r'\2\1', stringwithswappedwords)

def withoutre(basestring):
  asalist = list(basestring)
  asalist.reverse()
  for i in range(0, len(asalist), 2):
    asalist[i+1], asalist[i] = asalist[i], asalist[i+1]
  return ''.join(asalist)

s = '12345678'
print withre(s)
print withoutre(s)

Обратите внимание, что я установил s и опробовал два подхода для быстрой проверки работоспособности, что они на самом деле вычисляют один и тот же результат - в общем, хорошая практика для такого рода "гонок на равных"!

Затем в приглашении оболочки вы используете timeit следующим образом:

$ python -mtimeit -s'import swa' 'swa.withre(swa.s)'
78563412
78563412
10000 loops, best of 3: 42.2 usec per loop
$ python -mtimeit -s'import swa' 'swa.withoutre(swa.s)'
78563412
78563412
100000 loops, best of 3: 9.84 usec per loop

... и вы обнаружите, что в этом случае подход без RE работает примерно в 4 раза быстрее, что стоит оптимизации. Если у вас есть такой «измерительный жгут», можно легко поэкспериментировать с другими альтернативами и настройками для дальнейшей оптимизации, если, конечно, есть необходимость в «поистине невероятной скорости» в этой операции.

Редактировать : например, вот еще более быстрый подход (добавьте к тому же swa.py, с конечной строкой print faster(s), конечно; -):

def faster(basestring):
  asal = [basestring[i:i+2]
          for i in range(0, len(basestring), 2)]
  asal.reverse()
  return ''.join(asal)

Это дает:

$ python -mtimeit -s'import swa' 'swa.faster(swa.s)'
78563412
78563412
78563412
100000 loops, best of 3: 5.58 usec per loop

Около 5,6 микросекунд, по сравнению с 9,8 для простейшего подхода без RE, - это еще одна полезная микрооптимизация.

И так далее, конечно, есть старая народная (псевдо) теорема, которая гласит, что любую программу можно сделать как минимум на один байт короче и как минимум на одну наносекунду быстрее ...; -)

Редактировать : и, чтобы "доказать" псевдореему, вот совершенно другой подход (замените конец swa.py) ...:

import array
def witharray(basestring):
  a2 = array.array('H', basestring)
  a2.reverse()
  return a2.tostring()

s = '12345678'
# print withre(s)
# print withoutre(s)
print faster(s)
print witharray(s)

Это дает:

$ python -mtimeit -s'import swa' 'swa.witharray(swa.s)'
78563412
78563412
100000 loops, best of 3: 3.01 usec per loop

для дальнейшего возможного ускорения.

2 голосов
/ 19 января 2010
import re
re.sub(r'(..)(..)', r'\2\1', '12345678')
re.sub(r'(....)(....)', r'\2\1', '34127856')
1 голос
/ 19 января 2010

только для строки "12345678"

from textwrap import wrap
s="12345678"
t=wrap(s,len(s)/2)
a,b=wrap(t[0],len(t[0])/2)
c,d=wrap(t[1],len(t[1])/2)
a,b=b,a
c,d=d,c
print a+b+c+d

Вы можете сделать это универсальной функцией, чтобы сделать строку переменной длины.

выход

$ ./python.py
34127856
0 голосов
/ 28 сентября 2012

Я использую следующий подход:

data = "deadbeef"
if len(data) == 4: #2 bytes, 4 characters
   value = socket.ntohs(int(data, 16))
elif len(data) >= 8:
   value = socket.ntohl(int(data, 16))
else:
   value = int(data, 16)

у меня работает!

0 голосов
/ 19 января 2010

Если вы хотите сделать преобразование порядка байтов , используйте Python struct module для исходных двоичных данных.

Если это не ваша цель, вот простой пример кода для перестановки одной строки из 8 символов:

def wordpairswapper(s):
    return s[6:8] + s[4:6] + s[2:4] + s[0:2]
0 голосов
/ 19 января 2010
>>> import re
>>> re.sub("(..)(..)","\\2\\1","12345678")
'34127856'
>>> re.sub("(....)(....)","\\2\\1","34127856")
'78563412'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...