Python - Flipping Binary 1's and 0's in a String

前端 未结 9 1858
日久生厌
日久生厌 2020-12-03 15:52

I\'m trying to take a binary number in string form and flip the 1\'s and 0\'s, that is, change all of the 1\'s in the string to 0\'s, and all of the 0\'s to 1\'s. I\'m new t

相关标签:
9条回答
  • 2020-12-03 16:09

    You've already marked an answer to this, but I haven't seen the method that I would prefer. I'm assuming here that you have a binary number of known length - 8 bits in the examples I am giving.

    If you can start with the number as just a number, you can do the following:

    myNumber = 0b10010011
    myNumberInverted = myNumber ^ 0b11111111
    

    The ^ operator performs a bitwise XOR.

    If you really do have to start with a string, you can convert to an integer first and then perform this operation.

    myString = '10010011'
    myNumber = int(myString, 2)
    myNumberInverted = myNumber ^ 0b11111111
    
    0 讨论(0)
  • 2020-12-03 16:10

    Some things have changed since this question was answered. Hopefully my update proves useful to someone.

    The translate method is the fastest for me. Full test code follows.

    Thank you to those who contributed previously to allow me to test this.

    # System & Software
    # core i7 4790k @ ~ 4.6 GHz   32 GB RAM   Samsung Evo NVME
    # Visual Studio 2019 16.3.6
    
    # I do not understand Will's bit manipulation code
    # worst times shown in comments
    # ordered by speed on my system
    
    import timeit # required to use timeit
    import string # Required to call maketrans function.
    
    # https://www.afternerd.com/blog/timeit-multiple-lines/
    # if you are trying to time slightly longer pieces of code than a single line
    # timeit wants a string
    
    
    # the syntax  b_string.translate(maketrans("10", "01"))
    # presented by Muhammad Alkarouri does not appear to be valid anymore
    # i suspect this is due to changes within python versions
    a1_bit_flip = """\
    a1 = 0b1101010001101111 # accepts the binary input but will store it as an int
    a1_bin = bin(a1)[2:]
    # creates a string of the binary form of the integer minus the first 2 characters
    flip_bin_a1 = a1_bin.translate(str.maketrans("10","01"))"""
    
    trans_time = timeit.timeit(a1_bit_flip, number=100000) # time 100k iterations
    print('translate time')
    print(trans_time / 100000)
    # determine average time of a single iteration ~ 0.6282 us
    print('\n')
    
    
    
    a2_bit_flip = """\
    a2 = 0b1101010001101111
    a2_bin = bin(a2)[2:]
    a2_bin.replace('1', '2').replace('0', '1').replace('2', '0')"""
    
    replace_time = timeit.timeit(a2_bit_flip, number=100000) # time 100k iterations
    print('replace time')
    print(replace_time / 100000)
    # determine average time of a single iteration ~ 0.7557 us
    print('\n')
    
    
    
    a3_bit_flip = """\
    a3 = 0b1101010001101111
    a3_bin = bin(a3)[2:]
    bin((int(a3_bin, 2) ^ (2**(len(a3_bin)+1) - 1)))[3:]"""
    # I do not understand this line (Will)
    
    bin_bit_time = timeit.timeit(a3_bit_flip, number=100000)
    # time 100k iterations
    print('bin_bit time')
    print(bin_bit_time / 100000)
    # determine average time of a single iteration ~ 1.14 us
    print('\n')
    
    
    
    a4_bit_flip = """\
    a4 = 0b1101010001101111
    a4_bin = bin(a4)[2:]
    bin((i ^ (2 ** (i.bit_length()+1) - 1)))[3:]"""
    # I do not understand this line (Will)
    
    int_bit_time = timeit.timeit(a3_bit_flip, number=100000) # time 100k iterations
    print('int_bit time')
    print(int_bit_time / 100000)
    # determine average time of a single iteration ~ 1.14 us
    print('\n')
    
    
    
    join_bit_flip = """\
    a0 = 0b1101010001101111 # accepts the binary input but will store it as an int
    a0_bin = bin(a0)[2:]
    # creates a string of the binary form of the integer minus the first 2 characters
    flip_a0 = "".join('1' if x == '0' else '0' for x in a0_bin)""" # (Amber)
    
    join_time = timeit.timeit(join_bit_flip, number=100000) # time 100k iterations
    print('join time')
    print(join_time / 100000)
    # determine average time of a single iteration ~ 14.511 us
    print('\n')
    
    0 讨论(0)
  • 2020-12-03 16:11

    If speed is important:

    And you already have the decimal integer representing the binary string, then bit manipulation is slightly faster.

    bin((i ^ (2 ** (i.bit_length()+1) - 1)))[3:]
    

    If you are only given the binary string, then use the str.replace method given by @Amy:

    s.replace('1', '2').replace('0', '1').replace('2', '0')
    

    I tested the various methods proposed here, and the bit manipulation method, with this gist:

    Test Results

    i = 129831201;
    s = '111101111010001000100100001';
    

    Bit manipulation given decimal int:

    bin((i ^ (2 ** (i.bit_length()+1) - 1)))[3:]
    
    1000000 loops, best of 3: 0.647 usec per loop
    

    Bit manipulation given binary string:

    bin((int(s, 2) ^ (2**(len(s)+1) - 1)))[3:]
    
    1000000 loops, best of 3: 0.922 usec per loop
    

    Sequential str.replace:

    s.replace('1', '2').replace('0', '1').replace('2', '0')
    
    1000000 loops, best of 3: 0.619 usec per loop
    

    str.maketrans:

    s.translate(str.maketrans('10', '01'))
    
    1000000 loops, best of 3: 1.16 usec per loop
    

    ''.join with dictionary mapping:

    flip = {'1':'0', '0':'1'}; ''.join(flip[b] for b in s)
    
    100000 loops, best of 3: 2.78 usec per loop
    

    ''.join with conditional:

    ''.join('1' if b == '0' else '0' for b in s)
    
    100000 loops, best of 3: 2.82 usec per loop
    
    0 讨论(0)
  • 2020-12-03 16:11

    Using a dictionary should be very straightforward.

    >>> flip={"1":"0","0":"1"}
    >>> s="100011"
    >>> import sys
    >>> for i in s:
    ...   sys.stdout.write(flip[i])
    ...
    011100
    
    0 讨论(0)
  • 2020-12-03 16:14

    Amber's answer, while superior, possibly isn't the most clear, so here's a super basic iterative example:

    b_string = "1100101"
    ib_string = ""
    
    for bit in b_string:
      if bit == "1":
        ib_string += "0"
      else:
        ib_string += "1"
    
    print ib_string
    

    This can be done in much better ways...replacements, comprehensions, but this is an example.

    I would learn from the other answers in this question once you understand the basis of this one. This method is slow and painful. For the best performance, as Muhammad Alkarouri pointed out, the string.translate/maketrans combo is the way to go. Right behind it is the comprehension. My code is the slowest by a significant margin.

    0 讨论(0)
  • 2020-12-03 16:24

    http://docs.python.org/library/string.html#string.replace

    Replace all the 1's with 2's, then replace the 0's with 1's, finally replacing the 2's with 0's.

    "10011".replace("1", "2").replace("0", "1").replace("2", "0")
    
    0 讨论(0)
提交回复
热议问题