Path: ...!3.eu.feeder.erje.net!feeder.erje.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: "B. Pym" Newsgroups: comp.lang.lisp Subject: Vigenere Date: Mon, 17 Jun 2024 15:32:12 -0000 (UTC) Organization: A noiseless patient Spider Lines: 153 Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Injection-Date: Mon, 17 Jun 2024 17:32:12 +0200 (CEST) Injection-Info: dont-email.me; posting-host="90b6bfd3931bdb2bad5411c6c3dc2474"; logging-data="775894"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18+tY9ZNqbtLeMTR3zgnDCQ" User-Agent: XanaNews/1.18.1.6 Cancel-Lock: sha1:joWL7wuDUs5bLh/rAKV9EwXSqn4= Bytes: 5784 Pascal J. Bourguignon wrote: > tristanhennequin 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"