web-dev-qa-db-fra.com

comment faire de bitwise exclusif ou de deux chaînes en python?

Je voudrais effectuer une exclusivité de bitwise ou de deux chaînes en python, mais xor de chaînes ne sont pas autorisés en python. Comment puis-je le faire ?

41
Hick

Vous pouvez convertir les caractères en entiers et xor ceux-ci à la place:

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

Voici une fonction mise à jour au cas où vous auriez besoin d'une chaîne à la suite du 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))

Regardez le travail en ligne: ideone

56
Mark Byers

Si vous voulez utiliser des octets ou des mots, vous feriez mieux d'utiliser le type de tableau de Python au lieu d'une chaîne. Si vous travaillez avec des blocs de longueur fixe, vous pourrez peut-être utiliser le format H ou L pour utiliser des mots plutôt que des octets, mais je viens d'utiliser "B" pour cet exemple:

>>> 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'
24
Duncan

Pour les bytearrays, vous pouvez directement utiliser 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')
15
doep

Voici votre chaîne XOR'er, probablement pour une forme de cryptage légère:

>>> 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!

Notez que ceci est une forme de chiffrement extrêmement faible. Regardez ce qui se passe quand une chaîne vide à encoder:

>>> codebreak = xorWord("      ", code)
>>> print codebreak
SECRET
11
PaulMcG

la doublure pour python3 est: 

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

a, b et la valeur renvoyée sont bytes() au lieu de str() of course

ça ne peut pas être plus facile, j'adore python3 :)

9
yota
def strxor (s0, s1):
  l = [ chr ( ord (a) ^ ord (b) ) for a,b in Zip (s0, s1) ]
  return ''.join (l)

(Basé sur la réponse de Mark Byers.)

4
user81779

Si les chaînes ne sont même pas de même longueur, vous pouvez utiliser ceci

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)])])
3
Ashray Malhotra

Voulez-vous dire quelque chose comme ça:

s1 = '00000001'
s2 = '11111110'
int(s1,2) ^ int(s2,2)
2
satoru

La figure ci-dessous illustre la chaîne XORing s avec m, puis à nouveau pour inverser le processus:

>>> s='hello, world'
>>> m='markmarkmark'
>>> s=''.join(chr(ord(a)^ord(b)) for a,b in Zip(s,m))
>>> s
'\x05\x04\x1e\x07\x02MR\x1c\x02\x13\x1e\x0f'
>>> s=''.join(chr(ord(a)^ord(b)) for a,b in Zip(s,m))
>>> s
'hello, world'
>>>
1
Mark Tolonen
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)])
1
mckoss

J'ai trouvé que la méthode '' .join (chr (ord (a) ^ ord (b))) pour a, b dans Zip (s, m)) est assez lente. Au lieu de cela, j'ai fait ceci:

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
William McBrine

D'après la réponse de William McBrine, voici une solution pour les chaînes de longueur fixe qui est 9% plus rapide pour mon cas d'utilisation:

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'))
0
pts