Sujet : Vigenere
De : No_spamming (at) *nospam* noWhere_7073.org (B. Pym)
Groupes : comp.lang.lispDate : 17. Jun 2024, 17:32:12
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <v4pktn$nlmm$1@dont-email.me>
User-Agent : XanaNews/1.18.1.6
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"