web-dev-qa-db-ja.com

Python一度に2文字(ネットワークバイトオーダー)で文字列を反転します

この文字列があるとします。

ABCDEFGH

そして、次のようになるように逆にします。

GHEFCDAB

最も効率的な/ Pythonicソリューションは何でしょうか?私はいくつかの異なることを試しましたが、それらはすべてひどいように見えます...

前もって感謝します!

更新

誰かが興味を持っている場合、これは宿題のためではありませんでした。ネットワークキャプチャからのデータを処理し、それを16進バイトの文字列として返すスクリプトがありました。問題は、データがまだネットワークの順序にある​​ことでした。アプリの作成方法が原因で、戻ってたとえばsocket.htonsを使用したくなかったので、文字列を逆にしたかっただけです。

残念ながら、私の試みはとても恐ろしいようでした。もっと良い方法(よりPythonicな解決策)があるはずだとわかっていたので、ここで私の質問をします。

34
PeterM

これを行うための簡潔な方法は次のとおりです。

"".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']

次にそれを逆にし、最後に結果を連結して戻します。

33
Greg Hewgill

これを行うための楽しい方法がたくさん

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

誰かが興味を持っているなら、これはすべての*答えのタイミングです。

編集(最初にそれを間違えた):

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はあなたの仕事をすることができませんでした!

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

バイトオーダーではなく要素オーダーを交換したい場合は、a.byteswap()の代わりにa.reverse()を使用して終了します。

Trufaのベンチマークスクリプトを少し自由に編集しました。 変更されたスクリプト 生成された グラフィカルプロット すべての関数のほぼ線形のスケーリングを示しています。

7
Yann Vernier

これが一般的な形式です。グループ化のサイズは、一度に異なる文字数に簡単に変更できます。文字列の長さは、グループ化サイズの正確な倍数である必要があります

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

(これはPython 2、3では機能しません)

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

編集:呪い、明らかに別のポスターより27分遅い。しかし、私は逆スライス表記の方が好きです。

リバーススライスの詳細については、こちらをご覧ください: ""。join(reversed(val))vs val [::-1] ...これはpythonicですか?

3
elliot42

これを使用することはできますが、私がこのコードを書いた人には言わないでください:-)

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')
3
Alok Singhal

私の友人 Rob 美しい再帰的解決策を指摘しました:

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

そしてさらに別の方法:

a = "ABCDEFGH"
new = ""

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

print new
0
Trufa

これは、上記および現在のPython 3構文:

def reverse_hex(hex_string):
    if isinstance(hex_string, str):
        input_is_string = True
        hex_string = hex_string.encode()
    a = array.array('H', hex_string)
    a.reverse()
    output = a.tobytes()
    if input_is_string:
        return output.decode()
    else:
        return output
0
Utkonos

私はこのソリューションが最も単純で最も近いので最も好きです:

import struct
hex = struct.pack('<I', 0x41424344) #ABCD
print(hex) # BCDA
0
AK_

そして別の人が乗る...

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

ただのショット

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)に変更してください。これを、2つに分割するより良い方法があると確信しています。

pythonがs [::-1]について文句を言う場合は、reversed(s)を使用できます

0
Lacrymology

これは宿題のように見えます。それで、あなたが面白いと思うかもしれない非常に非正統的なアプローチがここにあります:

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

幸運を!

0
inspectorG4dget