Home > OS >  The while loop doesn't end but the condition is met
The while loop doesn't end but the condition is met

Time:11-18

I'm trying to code vigenere cypher so I need to have two lists of the same length. I thought everything will be okay with my solution but the while loop doesn't despite of the fact than condition is met. Because of that I got two list with different numbers of letters. Why this works like that and how to improve that. I am new programmer who learnt from books, so I haven't ever seen that while loop doesn't work properly. My code:

plaintext = "This is secret message"
plaintext = plaintext.upper()
key = "secret"
key = key.upper()
def encrypt_vigenere2( key, plaintext ):
    a = []
    b= []
    i = 0
    for letter in (plaintext):
        if letter != " ":
            a.append(letter)
    while i<len(a):
        for element in key:
            if element != " ":
                b.append(element)
                i  =1
    return a,b
print(encrypt_vigenere2(key,plaintext))

CodePudding user response:

The while loop does as expected, for you now you join the key until you reach the size of a,

b: ['S','E','C','R','E','T','S','E','C','R','E','T','S','E','C','R','E','T','S','E','C','R','E','T']

That will be useful for the next part : encryption

def encrypt_vigenere2(key, plaintext):
    ...
    result = ""
    for l, k in zip(a, b):
        result  = chr(((ord(l) - 65   ord(k) - 65) % 26)   65)
    return result

You can just use replace(" ", "") to remove the spaces, and to repeat the key, use itertools.cycle

from itertools import cycle

def encrypt_vigenere2(key, plaintext):
    result = ""
    for l, k in zip(plaintext.replace(" ", ""), cycle(key)):
        result  = chr(((ord(l) - 65   ord(k) - 65) % 26)   65)
    return result

CodePudding user response:

I am not sure if I understood your code right, but seems for me like you did not try to encrypt something. It looks like you tried to get the keystream, and correct me if I am wrong. But here is the code how to get the keystream:

def encrypt_vigenere3(key, plaintext):
    # variables
    a = [letter for letter in plaintext.upper() if letter != " "]
    b = [element for element in key.upper() if element != " "]
    keystream = []

    # creating the keystream
    i = 0
    current_num = 0
    while i <= len(a):
        if current_num == len(key):
            current_num = 0
        keystream.append(b[current_num])
        current_num  = 1
        i  = 1

    return keystream

I created the variables by "list comprehension". You should go look that term up, it makes your code way cleaner. And don't worry if it hard at the beginning, but once you understand it, it is really easy and usefull :)

CodePudding user response:

The idea for a vigenere encrypter program sounded nice to me so I did some coding and here is my result:

def encrypt_vigenere(plaintext, key):

    letter_matrix = [[chr(65   i) for i in range(26)] for j in range(26)]

    for index, column in enumerate(letter_matrix):

        for i in range(index):
            letter_matrix[index].append(column[0])
            del letter_matrix[index][0]

    plaintext = plaintext.upper()
    key = key.upper()
    keystream = ""
    ciphertext = ""

    current_letter = 0
    for letter in plaintext:
        if current_letter == len(key):
            current_letter = 0

        keystream  = key[current_letter]
        current_letter  = 1

    for letter_plaintext, letter_keystream in zip(plaintext.replace(" ", ""), keystream):
        ciphertext  = letter_matrix[ord(letter_plaintext)-65][ord(letter_keystream)-65]

    return ciphertext

You said that you were new to coding, so here are the things you might not now:

  • like previous said, list comprehension
  • chr() -> takes a number and assigns it to it corresponding ascii value
  • ord() -> the opposite of chr(). Takes letter and transforms it to ascii number
  • zip() -> goes trough two lists simultaneously

I hoped you learned something new :)

  • Related