hamza
hamza

Reputation: 2824

Index Error in python

I am new to programming, and I am trying to write a Vigenère Encryption Cipher using python. The idea is very simple and so is my function, however in this line:

( if((BinKey[i] == 'b')or(BinKey[i+1] == 'b')): ) 

It seems that I have an index problem, and I can't figure out how to fix it. The error message is:

IndexError: string index out of range

I tried to replace the i+1 index by another variable equal to i+1, since I thought that maybe python is re-incrementing the i, but it still won't work.

So my questions are:

  1. How to fix the problem, and what have I done wrong?

  2. Looking at my code, what can I learn to improve my programming skills?

  3. I want to build a simple interface to my program (which will contain all the encryption ciphers), and all I came up with from Google is pyqt, but it just seems too much work for a very simple interface, so is there a simpler way to build an interface? (I am working with Eclipse Indigo and pydev with Python3.x)

The Vigenère Encryption function (which contains the line that causes the problem) is:

def Viegner_Encyption_Cipher(Key,String):
    EncryptedMessage = ""
    i = 0
    j = 0
    BinKey = Bin_It(Key)
    BinString = Bin_It(String)
    BinKeyLengh = len(BinKey)
    BinStringLengh = len(BinString)
    while ((BinKeyLengh > i) and (BinStringLengh > j)):
        if((BinKey[i] == 'b')or(BinKey[i+1] == 'b')):
            EncryptedMessage = EncryptedMessage + BinKey[i]
        else:   
            EncryptedMessage = EncryptedMessage + Xor(BinKey[i],BinString[j])
        i = i + 1
        j = j + 1
        if (i == BinKeyLengh):
            i = i+j
    return EncryptedMessage

This is the Bin_It function:

 def Bin_It(String):
    TheBin = ""
    for Charactere in String:
         TheBin = TheBin + bin(ord(Charactere))
    return TheBin

And finally this is the Xor function:

def Xor(a,b):
    xor = (int(a) and not int(b)) or (not int(a) and int(b))
    if xor:
        return chr(1)
    else:
        return chr(0)

Upvotes: 4

Views: 220

Answers (4)

amaurea
amaurea

Reputation: 5067

In your while condition, you are ensuring that i < len(BinKey). This means that BinKey[i] will be valid, but BinKey[i+1] will not be valid at the last iteration of your loop, as you will then be accessing BinKey[len(BinKey)], which is one past the end of your string. Strings in python start at 0 and end at len-1 inclusive.

To avoid this, you can update your loop criterion to be

while BinKeyLength > i+1 and ...:

Upvotes: 4

Benjamin Hodgson
Benjamin Hodgson

Reputation: 44624

Looking at my code, what can I learn to improve my programming skills?

Looping over an index is not idiomatic Python. It's better to loop over the elements of an iterator where possible. After all, that's usually what you're interested in: for i in... is often followed by my_list[i].

In this example, you should use the built-in function zip (or itertools.izip if your code is lazy, though this isn't necessary in Python 3), which gives you pairs of values from two or more iterators, and stops when the shortest one is exhausted.

for key_char, string_char in zip(BinKey, BinString):  # takes values sequentially from
                                                      # BinKey and BinString
                                                      # and binds them to the names
                                                      # key_char and string_char
    # do processing on key_char and string_char

If you really must do a while loop on an index, then put the test the other way around so it's clearer what you're doing. Compare

while len(BinKey) > i and len(BinString) > j:  # this looks like len(BinKey) and
                                               # len(BinString) are varying and you're
                                               # comparing them to static variables i and j

with

while i < len(BinKey) and j < len(BinString):  # this looks like you're varying i and j
                                               # and comparing them to len(BinKey) and len(BinString)

Which better communicates the purpose of the loop?


Finally, the clause

if (i == BinKeyLengh):
    i = i+j

doesn't seem to do anything. If i == BinKeyLength then the while loop will stop in a moment anyway.

Upvotes: 2

kosklain
kosklain

Reputation: 399

I think your error, as Python interpreter says, is that you accessing invalid array positions. In order to solve this, unlike it's being said, you should change your code to

while (BinKeyLength > i+2 and ...):

This is because in the last step, BinKeyLength = i+2, then i+1 is BinKeyLength-1, which is the last position of your array.

Concerning your programming skills I recommend you two things:

  • Be the code. Sounds mystic but the most important thing that is missing here is figuring out which indices numbers are used.
  • As it has been said by rubik, follow some style guides like PEP8 style guide.

Upvotes: 1

alestanis
alestanis

Reputation: 21863

You can either change

while ((BinKeyLengh > i) and (BinStringLengh > j)):

to

while ((BinKeyLengh > i-1) and (BinStringLengh > j)):

or change

if((BinKey[i] == 'b')or(BinKey[i+1] == 'b')):

to

if((BinKey[i] == 'b') or (BinKeyLengh > i-1 and BinKey[i+1] == 'b')):

This will avoid trying to go into BinKey[BinKeyLength], which is out of scope.

Upvotes: 4

Related Questions