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

1

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

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

В результате я хочу "34127856"

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

  • 1
    если строка "123456789012", что должно быть на выходе?
Теги:
string
hex

6 ответов

4

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

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

Edit: Тем не менее, это определенно не самый быстрый подход в 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-less примерно в 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-less, является еще одной возможной микрооптимизацией.

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

Изменить: и "доказать" псевдотерам, здесь совершенно другой подход (замените конец 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

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

  • 0
    Молодец Алекс. Как только программист выбегает из зала зеркал с регулярными выражениями, он может делать великие дела ... Лично я хочу, чтобы все мои программы были в семь раз быстрее, чем мои конкуренты!
  • 0
    @cudamaru, последняя версия в 14 раз быстрее, чем у меня с RE, и в 3 раза быстрее, чем у меня без них. Быть загипнотизированным удобством РЗ до того, что они не рассматривают альтернативы, наверняка нанесет ущерб. Однако не стоит пренебрегать возможностью того, что (в других случаях) преимущества в скорости могут быть как раз наоборот - всегда рассматривайте и пробуйте различные разумные возможности, когда скорость действительно имеет значение! -)
Показать ещё 1 комментарий
2
import re
re.sub(r'(..)(..)', r'\2\1', '12345678')
re.sub(r'(....)(....)', r'\2\1', '34127856')
1

только для строки "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

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

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

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

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

def wordpairswapper(s):
    return s[6:8] + s[4:6] + s[2:4] + s[0:2]
0
>>> import re
>>> re.sub("(..)(..)","\\2\\1","12345678")
'34127856'
>>> re.sub("(....)(....)","\\2\\1","34127856")
'78563412'

Ещё вопросы

Сообщество Overcoder
Наверх
Меню