• Vigenere

    From B. Pym@21:1/5 to Pascal J. Bourguignon on Mon Jun 17 15:32:12 2024
    Pascal J. Bourguignon wrote:

    tristanhennequin <tristanhennequin@free.fr> writes:

    Hello,
    I 've just read the vigenere implementation published on rosetta code :

    I think it's very long and maybe clumsy.

    It's also wrong.

    (defun strip (s)
    (remove-if-not
    (lambda (c) (char<= #\A c #\Z))
    (string-upcase s)))

    There may be non alphabetic characters between A and Z. This functions rightfully doesn't use alpha-char-p, (because alpha-char-p may contain implementation defined characters), but it is wrong in using this simple comparison. Since we only want letters from A to Z, we must write it explicitely (or, possibly check that only letters from A to Z are
    between A and Z, but I have my doubts if this check can be done at compilation time).

    So:

    (defparameter alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ")

    (defun strip (s)
    (remove-if-not (lambda (c) (find (char-upcase c) alphabet)) s)



    (defun vigenère (s key &key decipher
    &aux (A (char-code #\A))
    (op (if decipher #'- #'+)))

    Personnally, I don't like using &aux for stylistic reasons (it puts in
    the signature of the function details that belong to the implementation.
    It's very rare to find a case where having those variable in the
    signature is justified. &aux is basically a ugly hack to do stuff in
    struct constructors).


    (labels
    ((to-char (c) (code-char (+ c A)))
    (to-code (c) (- (char-code c) A)))

    Again, this part makes a lot of assumptions that may be wrong. A better implementation is:

    (to-char (code) (aref code alphabet))
    (to-code (char) (position char alphabet))

    (let ((k (map 'list #'to-code (strip key))))
    (setf (cdr (last k)) k)
    (map 'string
    (lambda (c)
    (prog1
    (to-char
    (mod (funcall op (to-code c) (car k)) 26))
    (setf k (cdr k))))
    (strip s)))))

    This is not bad. What you can do here, is to use pop:

    (map 'string
    (lambda (c) (to-char (mod (funcall op (to-code c) (pop k)) 26)))
    (strip s))


    (let* ((msg "Beware the Jabberwock... The jaws that... the claws that catch!")
    (key "vigenere cipher")
    (enc (vigenère msg key))
    (dec (vigenère enc key :decipher t)))
    (format t "msg: ~a~%enc: ~a~%dec: ~a~%" msg enc dec))



    What is the most concise and short version of the vigenere encryption method can you produce in lisp?

    (defparameter alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ")

    (defun strip-non-letters (string)
    (remove-if-not (lambda (c) (find (char-upcase c) alphabet)) string))

    (defun ensure-circular (list)
    (setf (cdr (last list)) list))

    (defun vigenère (text key &key decipher)
    (flet ((to-char (code) (aref alphabet code))
    (to-code (char) (position char alphabet :test (function char-equal))))
    (declare (inline to-char to-code))
    (let ((op (if decipher (function -) (function +)))
    (offsets (ensure-circular (map 'list (function to-code) (strip-non-letters key)))))
    (map 'string
    (lambda (c) (to-char (mod (funcall op (to-code c) (pop offsets)) 26)))
    (strip-non-letters text)))))

    (let* ((msg "Beware the Jabberwock... The jaws that... the claws that catch!")
    (key "vigenere cipher")
    (enc (vigenère msg key))
    (dec (vigenère enc key :decipher t)))
    (format t "msg: ~a~%enc: ~a~%dec: ~a~%" msg enc dec))


    msg: Beware the Jabberwock... The jaws that... the claws that catch!
    enc: WMCEEIKLGRPIFVMEUGXXYILILZXYVBZLRGCEYAIOEKXIZGU
    dec: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH
    nil

    Gauche Scheme

    (use srfi-1) ;; circular-list

    (define alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ")

    (define (text->list str)
    (filter-map
    (lambda (c)
    (let ((x (char-upcase c))) (string-scan alphabet x)))
    (string->list str)))

    (define (list->text lst)
    (list->string
    (map
    (lambda (n) (string-ref alphabet n))
    lst)))

    (define (vig text key encrypt?)
    (list->text
    (map
    (lambda(n k) (mod ((if encrypt? + -) n k) 26))
    (text->list text)
    (apply circular-list (text->list key)))))

    (vig "Beware the Jabberwock... The jaws that... the claws that catch!"
    "vigenere cipher" #t)
    ===>
    "WMCEEIKLGRPIFVMEUGXXYILILZXYVBZLRGCEYAIOEKXIZGU"

    (vig "WMCEEIKLGRPIFVMEUGXXYILILZXYVBZLRGCEYAIOEKXIZGU"
    "vigenere cipher" #f)
    ===>
    "BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH"

    (vig "W M C E EIKLGRPIFVMEUGXXYILILZXYVBZLRGCEYAIOEKXIZGU"
    "vigenere cipher" #f)
    ===>
    "BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)