Реверс строки в Python два символа за раз (порядок байтов сети)

скажем, у вас есть эта строка:

ABCDEFGH

и вы хотите изменить его так, чтобы он стал:

GHEFCDAB

что бы быть наиболее эффективным / подходящие для Python решение? Я пробовал несколько разных вещей, но все они выглядят ужасно...

спасибо заранее!

обновление:

в случае, если кто-то заинтересован, это было не для домашней работы. У меня был скрипт, который обрабатывал данные из сетевого захвата и возвращал их как строка шестнадцатеричных байтов. Проблема была данные еще в сетевом порядке. Из-за того, как было написано приложение, я не хотел возвращаться и пытаться использовать say socket.htons, я просто хотел обратного строку.

12 ответов


краткий способ сделать это:

"".join(reversed([a[i:i+2] for i in range(0, len(a), 2)]))

это работает, сначала разбивая строку на пары:

>>> [a[i:i+2] for i in range(0, len(a), 2)]
['AB', 'CD', 'EF', 'GH']

затем обратить это вспять и, наконец, объединить результат вместе.


много интересных способов сделать это

>>> s="ABCDEFGH"
>>> "".join(map(str.__add__, s[-2::-2] ,s[-1::-2]))
'GHEFCDAB'

если кто-то заинтересован, это время для всех* ответы.

EDIT (ошибся в первый раз):

import timeit
import struct

string = "ABCDEFGH"

# Expected resutlt => GHEFCDAB

def rev(a):
    new = ""

    for x in range(-1, -len(a), -2):
        new += a[x-1] + a[x]

    return new

def rev2(a):
    return "".join(reversed([a[i:i+2] for i in range(0, len(a), 2)]))

def rev3(a):
    return "".join(map(str.__add__, a[-2::-2] ,a[-1::-2]))

def rev4(a):
    return "".join(map("".join, reversed(zip(*[iter(a)]*2))))


def rev5(a):
    n = len(a) / 2
    fmt = '%dh' % n
    return struct.pack(fmt, *reversed(struct.unpack(fmt, a)))

def rev6(a):
    return "".join([a[x:x+2] for x in range(0,len(a),2)][::-1])


print "Greg Hewgill %f" %timeit.Timer("rev2(string)", "from __main__ import rev2, string").timeit(100000)
print "gnibbler %f" %timeit.Timer("rev3(string)", "from __main__ import rev3, string").timeit(100000)
print "gnibbler second %f" %timeit.Timer("rev4(string)", "from __main__ import rev4, string").timeit(100000)
print "Alok %f" %timeit.Timer("rev5(string)", "from __main__ import rev5, struct, string").timeit(100000)
print "elliot42 %f" %timeit.Timer("rev6(string)", "from __main__ import rev6, struct, string").timeit(100000)
print "me %f" %timeit.Timer("rev(string)", "from __main__ import rev, string").timeit(100000)

результаты string = "ABCDEFGH":

Greg Hewgill 0.853000
gnibbler 0.428000
gnibbler second 0.707000
Alok 0.763000
elliot42 0.237000
me 0.200000

результаты string = "ABCDEFGH"*5:

Greg Hewgill 2.246000
gnibbler 0.811000
gnibbler second 1.205000
Alok 0.972000
elliot42 0.594000
me 0.584000

результаты string = "ABCDEFGH"*10:

Greg Hewgill 2.058000
gnibbler 1.178000
gnibbler second 1.926000
Alok 1.210000
elliot42 0.935000
me 1.082000

результаты string = "ABCDEFGH"*100:

Greg Hewgill 9.762000
gnibbler 9.134000
gnibbler second 14.782000
Alok 5.775000
elliot42 7.351000
me 18.140000

*извините @Lacrymology не может сделать вашу работу!


>>> import array
>>> s="abcdef"
>>> a=array.array('H',s)
>>> a.byteswap()
>>> a.tostring()
'badcfe'

завершить с помощью a.reverse () вместо a.byteswap (), если вы хотите поменять порядок элементов, а не порядок байтов.

Я взял на себя смелость немного отредактировать тестовый скрипт Trufa. The изменен скрипт создан графический участка отображение приблизительно линейного масштабирования для всех функций.


вот общая форма. Размер группировки можно легко изменить на другое количество символов за раз. Длина строки должна быть точной кратной размеру группировки

>>> "".join(map("".join, reversed(zip(*[iter("ABCDEFGH")]*2))))
'GHEFCDAB'

(Это Python 2, он не будет работать в 3)


вы можете использовать это, но не говорите никому, что я написал этот код: -)

import struct

def pair_reverse(s):
    n = len(s) / 2
    fmt = '%dh' % n
    return struct.pack(fmt, *reversed(struct.unpack(fmt, s)))

pair_reverse('ABCDEFGH')

st = "ABCDEFGH"
"".join([st[x:x+2] for x in range(0,len(st),2)][::-1])

EDIT: проклятия, по-видимому, на 27 минут медленнее, чем другой плакат. Но мне больше нравится нотация обратного среза.

дополнительная информация об обратном срезе здесь:"".join(reversed (val)) vs val[::-1]...что такое питон?


мой друг Роб указал на красивое рекурсивное решение:

def f(s):
    return "" if not s else f(s[2:]) + s[:2]

просто удар

st = "ABCDEFGH"
s = [st[2*n:2*n+1] for n in range(len(st)/2)]
return s[::-1].join('')

это предполагает, что len(st) четный, в противном случае измените это на range(len(st)/2+1), и я даже уверен, что есть лучший способ сделать это разделить на двойки.

Если ваш python жалуется на s [:: -1] вы можете использовать reversed(s)


и еще один способ:

a = "ABCDEFGH"
new = ""

for x in range(-1, -len(a), -2):
    new += a[x-1] + a[x]

print new

это похоже на домашнюю работу. Итак, вот очень неортодоксальный подход, который может вас заинтересовать:

>>> s = "ABCDEFGH"
>>> ''.join([s[::2][::-1][i]+s[::-2][i] for i in range(len(s[::2]))])
'GHEFCDAB'

Удачи!


и еще попадет...

>>> rev = "ABCDEFGH"[::-1]
>>> ''.join([''.join(el) for el in zip(rev[1::2], rev[0::2])])
'GHEFCDAB'