I would like to perform a bitwise exclusive or of two strings in python, but xor of strings are not allowed in python. How can I do it ?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You can convert the characters to integers and xor those instead:
l = [ord(a) ^ ord(b) for a,b in zip(s1,s2)]
Here’s an updated function in case you need a string as a result of the 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))
See it working online: ideone
Method 2
If you want to operate on bytes or words then you’ll be better to use Python’s array type instead of a string. If you are working with fixed length blocks then you may be able to use H or L format to operate on words rather than bytes, but I just used ‘B’ for this example:
>>> 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()
';x00x0fx1enXS2x0cx00tx10R'
Method 3
For bytearrays you can directly use 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'GWBx00TAG')
Method 4
Here is your string XOR’er, presumably for some mild form of encryption:
>>> 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 ';x00x0fx1enXS2x0cx00tx10R' >>> decrypt = xorWord(encrypt,code) >>> print decrypt Hello, World!
Note that this is an extremely weak form of encryption. Watch what happens when given a blank string to encode:
>>> codebreak = xorWord(" ", code)
>>> print codebreak
SECRET
Method 5
the one liner for python3 is :
def bytes_xor(a, b) :
return bytes(x ^ y for x, y in zip(a, b))
where a, b and the returned value are bytes() instead of str() of course
can’t be easier, I love python3 🙂
Method 6
def strxor (s0, s1): l = [ chr ( ord (a) ^ ord (b) ) for a,b in zip (s0, s1) ] return ''.join (l)
(Based on Mark Byers answer.)
Method 7
If the strings are not even of equal length, you can use this
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)])])
Method 8
Do you mean something like this:
s1 = '00000001' s2 = '11111110' int(s1,2) ^ int(s2,2)
Method 9
Below illustrates XORing string s with m, and then again to reverse the process:
>>> s='hello, world' >>> m='markmarkmark' >>> s=''.join(chr(ord(a)^ord(b)) for a,b in zip(s,m)) >>> s 'x05x04x1ex07x02MRx1cx02x13x1ex0f' >>> s=''.join(chr(ord(a)^ord(b)) for a,b in zip(s,m)) >>> s 'hello, world' >>>
Method 10
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)])
Method 11
I’ve found that the ”.join(chr(ord(a)^ord(b)) for a,b in zip(s,m)) method is pretty slow. Instead, I’ve been doing this:
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)))
Method 12
Based on William McBrine’s answer, here is a solution for fixed-length strings which is 9% faster for my use case:
import itertools
import struct
def make_strxor(size):
def strxor(a, b, izip=itertools.izip, pack=struct.pack, unpack=struct.unpack, fmt='%dB' % size):
return pack(fmt, *(a ^ b for a, b in izip(unpack(fmt, a), unpack(fmt, b))))
return strxor
strxor_3 = make_strxor(3)
print repr(strxor_3('foo', 'bar'))
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0