Task

Implement a   Vigenère cypher,   both encryption and decryption.

The program should handle keys and text of unequal length,
and should capitalize everything and discard non-alphabetic characters. 

(If your program handles non-alphabetic characters in another way,
make a note of it.)



Related tasks

   Caesar cipher
   Rot-13
   Substitution Cipher


/* NetRexx */
options replace format comments java crossref savelog symbols nobinary
 
pt  = 'Attack at dawn!'
key = 'LEMON'
test(key, pt)
 
key = 'N' -- rot-13
test(key, pt)
 
key = 'B' -- Caesar
test(key, pt)
 
pt = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
key = 'A'
test(key, pt)
 
pt = sampledata()
key = 'Hamlet; Prince of Denmark'
test(key, pt)
 
return
 
method vigenere(meth, key, text) public static
 
  select
    when 'encipher'.abbrev(meth.lower, 1) then df = 1
    when 'decipher'.abbrev(meth.lower, 1) then df = -1
    otherwise signal IllegalArgumentException(meth 'must be "encipher" or "decipher"')
    end
 
  alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
  text = stringscrubber(text)
  key  = stringscrubber(key)
  code = ''
  loop l_ = 1 to text.length()
    M = alpha.pos(text.substr(l_, 1)) - 1
    k_ = (l_ - 1) // key.length()
    K = alpha.pos(key.substr(k_ + 1, 1)) - 1
    C = mod((M + K * df), alpha.length())
    C = alpha.substr(C + 1, 1)
    code = code || C
    end l_
 
  return code
 
method vigenere_encipher(key, plaintext) public static
 
  return vigenere('encipher', key, plaintext)
 
method vigenere_decipher(key, ciphertext) public static
 
  return vigenere('decipher', key, ciphertext)
 
method mod(N = int, D = int) private static
 
return (D + (N // D)) // D
 
method stringscrubber(cleanup) private static
 
  alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
  cleanup = cleanup.upper.space(0)
  loop label f_ forever
    x_ = cleanup.verify(alpha)
    if x_ = 0 then leave f_
    cleanup = cleanup.changestr(cleanup.substr(x_, 1), '')
    end f_
 
  return cleanup
 
method test(key, pt) private static
 
  ct = vigenere_encipher(key, pt)
  display(ct)
  dt = vigenere_decipher(key, ct)
  display(dt)
 
  return
 
method display(text) public static
 
  line = ''
  o_ = 0
  loop c_ = 1 to text.length()
    b_ = o_ // 5
    o_ = o_ + 1
    if b_ = 0 then line = line' '
    line = line || text.substr(c_, 1)
    end c_
 
  say '....+....|'.copies(8)
  loop label l_ forever
    parse line w1 w2 w3 w4 w5 w6 W7 w8 w9 w10 w11 w12 line
    pline = w1 w2 w3 w4 w5 w6 w7 w8 w9 w10 w11 w12
    say pline.strip()
    if line.strip().length() = 0 then leave l_
    end l_
  say
 
  return
 
method sampledata() private static returns Rexx
 
  NL = char('\n')  
  antic_disposition = Rexx[]
 
  antic_disposition = [                                         -
    Rexx("To be, or not to be--that is the question:"        ), -
    Rexx("Whether 'tis nobler in the mind to suffer"         ), -
    Rexx("The slings and arrows of outrageous fortune"       ), -
    Rexx("Or to take arms against a sea of troubles"         ), -
    Rexx("And by opposing end them. To die, to sleep--"      ), -
    Rexx("No more--and by a sleep to say we end"             ), -
    Rexx("The heartache, and the thousand natural shocks"    ), -
    Rexx("That flesh is heir to. 'Tis a consummation"        ), -
    Rexx("Devoutly to be wished. To die, to sleep--"         ), -
    Rexx("To sleep--perchance to dream: ay, there's the rub,"), -
    Rexx("For in that sleep of death what dreams may come"   ), -
    Rexx("When we have shuffled off this mortal coil,"       ), -
    Rexx("Must give us pause. There's the respect"           ), -
    Rexx("That makes calamity of so long life."              ), -
    Rexx("For who would bear the whips and scorns of time,"  ), -
    Rexx("Th' oppressor's wrong, the proud man's contumely"  ), -
    Rexx("The pangs of despised love, the law's delay,"      ), -
    Rexx("The insolence of office, and the spurns"           ), -
    Rexx("That patient merit of th' unworthy takes,"         ), -
    Rexx("When he himself might his quietus make"            ), -
    Rexx("With a bare bodkin? Who would fardels bear,"       ), -
    Rexx("To grunt and sweat under a weary life,"            ), -
    Rexx("But that the dread of something after death,"      ), -
    Rexx("The undiscovered country, from whose bourn"        ), -
    Rexx("No traveller returns, puzzles the will,"           ), -
    Rexx("And makes us rather bear those ills we have"       ), -
    Rexx("Than fly to others that we know not of?"           ), -
    Rexx("Thus conscience does make cowards of us all,"      ), -
    Rexx("And thus the native hue of resolution"             ), -
    Rexx("Is sicklied o'er with the pale cast of thought,"   ), -
    Rexx("And enterprise of great pith and moment"           ), -
    Rexx("With this regard their currents turn awry"         ), -
    Rexx("And lose the name of action. -- Soft you now,"     ), -
    Rexx("The fair Ophelia! -- Nymph, in thy orisons"        ), -
    Rexx("Be all my sins remembered."                        )  -
    ]
 
    melancholy_dane = Rexx('')
    loop l_ = 0 for antic_disposition.length
      melancholy_dane = melancholy_dane || antic_disposition[l_] || NL
      end l_
 
    return melancholy_dane
 