как сделать побитовый эксклюзив или из двух строк в Python? - PullRequest
43 голосов
/ 10 апреля 2010

Я хотел бы выполнить побитовое исключение или две строки в Python, но xor строк не разрешены в Python Как я могу это сделать?

Ответы [ 12 ]

58 голосов
/ 10 апреля 2010

Вы можете преобразовать символы в целые числа и вместо них использовать xor:

l = [ord(a) ^ ord(b) for a,b in zip(s1,s2)]

Вот обновленная функция, если вам нужна строка в результате XOR:

def sxor(s1,s2):    
    # convert strings to a list of character pair tuples
    # go through each tuple, converting them to ASCII code (ord)
    # perform exclusive or on the ASCII code
    # then convert the result back to ASCII (chr)
    # merge the resulting array of characters as a string
    return ''.join(chr(ord(a) ^ ord(b)) for a,b in zip(s1,s2))

Посмотрите, как работает онлайн: ideone

24 голосов
/ 10 апреля 2010

Если вы хотите работать с байтами или словами, вам лучше использовать тип массива Python вместо строки. Если вы работаете с блоками фиксированной длины, вы можете использовать формат H или L для работы со словами, а не байтами, но я просто использовал «B» для этого примера:

>>> import array
>>> a1 = array.array('B', 'Hello, World!')
>>> a1
array('B', [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33])
>>> a2 = array.array('B', ('secret'*3))
>>> for i in range(len(a1)):
    a1[i] ^= a2[i]


>>> a1.tostring()
';\x00\x0f\x1e\nXS2\x0c\x00\t\x10R'
15 голосов
/ 27 февраля 2013

Для байтовых массивов вы можете напрямую использовать XOR:

>>> b1 = bytearray("test123")
>>> b2 = bytearray("321test")
>>> b = bytearray(len(b1))
>>> for i in range(len(b1)):
...   b[i] = b1[i] ^ b2[i]

>>> b
bytearray(b'GWB\x00TAG')
12 голосов
/ 10 апреля 2010

Вот ваша строка XOR'er, предположительно для некоторой легкой формы шифрования:

>>> src = "Hello, World!"
>>> code = "secret"
>>> xorWord = lambda ss,cc: ''.join(chr(ord(s)^ord(c)) for s,c in zip(ss,cc*100))
>>> encrypt = xorWord(src, code)
>>> encrypt
';\x00\x0f\x1e\nXS2\x0c\x00\t\x10R'
>>> decrypt = xorWord(encrypt,code)
>>> print decrypt
Hello, World!

Обратите внимание, что это крайне слабая форма шифрования. Посмотрите, что произойдет, если дать пустую строку для кодирования:

>>> codebreak = xorWord("      ", code)
>>> print codebreak
SECRET
9 голосов
/ 12 февраля 2015

один вкладыш для python3:

def bytes_xor(a, b) :
    return bytes(x ^ y for x, y in zip(a, b))

, где a, b и возвращаемое значение bytes() вместо str(), конечно

не может быть проще, я люблю python3:)

4 голосов
/ 21 марта 2012
def strxor (s0, s1):
  l = [ chr ( ord (a) ^ ord (b) ) for a,b in zip (s0, s1) ]
  return ''.join (l)

(на основании ответа Марка Байерса.)

3 голосов
/ 28 июня 2013

Если строки даже не равны по длине, вы можете использовать это

def strxor(a, b):     # xor two strings of different lengths
    if len(a) > len(b):
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
    else:
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])
2 голосов
/ 10 апреля 2010

Вы имеете в виду что-то вроде этого:

s1 = '00000001'
s2 = '11111110'
int(s1,2) ^ int(s2,2)
1 голос
/ 22 октября 2013

Я обнаружил, что метод '.join (chr (ord (a) ^ ord (b))) для a, b в zip (s, m)) довольно медленный. Вместо этого я делал это:

fmt = '%dB' % len(source)
s = struct.unpack(fmt, source)
m = struct.unpack(fmt, xor_data)
final = struct.pack(fmt, *(a ^ b for a, b in izip(s, m)))
1 голос
/ 13 января 2012
def xor_strings(s1, s2):
    max_len = max(len(s1), len(s2))
    s1 += chr(0) * (max_len - len(s1))
    s2 += chr(0) * (max_len - len(s2))
    return ''.join([chr(ord(c1) ^ ord(c2)) for c1, c2 in zip(s1, s2)])
...