Racket/base24
Från Täpp-Anders
Hoppa till navigeringHoppa till sök
#lang racket
;;;;;
;; BASE24 encoder/decoder
;; Täpp-Anders Sikvall, anders@sikvall.se, 2026-04-07
;;
;; USAGE
;; racket base24.rkt --encode < INPUT_FILE > OUTPUT_FILE
;; racket base24.rkt --decode < INPUT_FILE > OUTPUT_FILE
;;
;; COMMENT
;; This does not precede the coded data with any kind of header
;; and the error control and handling is abysmally minimal but
;; it shows the ease of implementing something like this compared
;; to languages like C.
;;
;; EXPLANATION
;; The program treats the entire input as a bignum and then basically
;; converts it to the output by repeated division and looking up the
;; quotient in the BASE24 alphabet. Since the bignum implementation
;; is so efficient in Racket/Scheme this means it will be effective
;; even for moderately large files.
;;
;;
;; BASE24 Alfabet (exkluderar förväxlingsbara tecken)
(define alphabet "BCDFGHJKMPQRTVWXY2346789")
(define base 24)
(define max-col 68)
;; Skapar en map för snabb uppslagning vid avkodning
(define char-to-val
(for/hash ([c (in-string alphabet)]
[i (in-naturals)])
(values c i)))
;; Hjälpfunktion för att skriva ut med radbrytningar
(define (display-with-breaks str)
(let loop ([remaining str])
(cond
[(<= (string-length remaining) max-col)
(displayln remaining)]
[else
(displayln (substring remaining 0 max-col))
(loop (substring remaining max-col))])))
;; --- ENCODER ---
(define (encode)
(let* ([input-bytes (port->bytes (current-input-port))]
[num (bytes->integer input-bytes)])
(if (zero? num)
(displayln (string-ref alphabet 0))
(let loop ([n num] [res '()])
(if (zero? n)
(display-with-breaks (list->string res))
(loop (quotient n base)
(cons (string-ref alphabet (remainder n base)) res)))))))
;; --- DECODER ---
(define (decode)
;; Vi rensar bort eventuella radbrytningar/whitespaces innan vi avkodar
(let* ([raw-input (port->string (current-input-port))]
[input-str (regexp-replace* #px"\\s+" raw-input "")]
[num (for/fold ([n 0])
([char (in-string input-str)])
(+ (* n base) (hash-ref char-to-val char)))])
(display (integer->bytes num))))
;; --- KONVERTERINGSFUNKTIONER ---
(define (bytes->integer b)
(for/fold ([n 0])
([byte (in-bytes b)])
(+ (arithmetic-shift n 8) byte)))
(define (integer->bytes n)
(if (zero? n)
(bytes 0)
(let loop ([i n] [res '()])
(if (zero? i)
(list->bytes res)
(loop (arithmetic-shift i -8)
(cons (bitwise-and i #xFF) res))))))
;; --- CLI HANTERING ---
(define (main)
(match (current-command-line-arguments)
[(vector (or "--encode" "-e")) (encode)]
[(vector (or "--decode" "-d")) (decode)]
[_ (displayln "Användning: racket base24.rkt [--encode | --decode]")]))
(main)