Problem 17

(defvar num-str-alist
  '((1 . "one")
    (2 . "two")
    (3 . "three")
    (4 . "four")
    (5 . "five")
    (6 . "six")
    (7 . "seven")
    (8 . "eight")
    (9 . "nine")
    (10 . "ten")
    (11 . "eleven")
    (12 . "twelve")
    (13 . "thirteen")
    (14 . "fourteen")
    (15 . "fifteen")
    (16 . "sixteen")
    (17 . "seventeen")
    (18 . "eighteen")
    (19 . "nineteen")
    (20 . "twenty")
    (30 . "thirty")
    (40 . "forty")
    (50 . "fifty")
    (60 . "sixty")
    (70 . "seventy")
    (80 . "eighty")
    (90 . "ninety")))

(defvar separator-alist
    '((1 . "thousand")
      (2 . "million")
      (3. "billion")))

(defun assq-val (key alist)
  (cdr (assq key alist)))

(defun assq-num-str (n)
  (assq-val n num-str-alist))

(defun assq-separator (base)
  (assq-val base separator-alist))

(defun convert-1-99 (n)
  (if (< n 20)
      (assq-num-str n)
    (if (eq (% n 10) 0)
	(assq-num-str n)
      (concat (assq-num-str (* (/ n 10) 10))
	      "-"
	      (assq-num-str (% n 10)) ))))

(defun convert-1-999 (n)
  (if (< n 100)
      (convert-1-99 n)
    (if (eq (% n 100) 0)
	(concat (assq-num-str (/ n 100)) " hundred")
      (concat (assq-num-str (/ n 100)) " hundred and "
	      (convert-1-99 (% n 100))) )))

(defun separate-num (n)
  (let (lst)
    (while (not (eq n 0))
      (setq lst (cons (% n 1000) lst))
      (setq n (/ n 1000)))
    lst ))

(defun convert-num-str-1 (n base)
  (if (eq base 0)
      (concat (convert-1-999 n))
    (concat (convert-1-999 n) " " (assq-separator base)) ))

(defun convert-num-str (n)
  (let* ((sep-n (separate-num n)) (base (1- (length sep-n))) str)
    (setq str (convert-num-str-1 (car sep-n) base))
    (setq sep-n (cdr sep-n))
    (setq base (1- base))
    (while sep-n
      (setq str (concat str " " (convert-num-str-1 (car sep-n) base)))
      (setq sep-n (cdr sep-n))
      (setq base (1- base)) )
    str ))

(with-temp-buffer
  (let ((n 1) (limit (string-to-number (car argv))))
    (while (<= n limit)
      (insert (concat (convert-num-str n) " "))
      (setq n (1+ n)) ))
  (princ (buffer-string))
  (let ((num-of-char 0))
    (goto-char (point-min))
    (while (re-search-forward "\\w" nil t)
      (setq num-of-char (1+ num-of-char)) )
    (princ num-of-char)
    (princ "\n") ))