1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-11 00:00:49 +02:00
guile/module/slib/chap.scm
2001-04-14 11:24:45 +00:00

150 lines
4.5 KiB
Scheme

;;;; "chap.scm" Chapter ordering -*-scheme-*-
;;; Copyright 1992, 1993, 1994 Aubrey Jaffer.
;
;Permission to copy this software, to redistribute it, and to use it
;for any purpose is granted, subject to the following restrictions and
;understandings.
;
;1. Any copy made of this software must include this copyright notice
;in full.
;
;2. I have made no warrantee or representation that the operation of
;this software will be error-free, and I am under no obligation to
;provide any services, by way of maintenance, update, or otherwise.
;
;3. In conjunction with products arising from the use of this
;material, there shall be no use of my name in any advertising,
;promotional, or sales literature without prior written consent in
;each case.
;;; The CHAP: functions deal with strings which are ordered like
;;; chapters in a book. For instance, a_9 < a_10 and 4c < 4aa. Each
;;; section of the string consists of consecutive numeric or
;;; consecutive aphabetic characters.
(define (chap:string<? s1 s2)
(let ((l1 (string-length s1))
(l2 (string-length s2)))
(define (match-so-far i ctypep)
(cond ((>= i l1) (not (>= i l2)))
((>= i l2) #f)
(else
(let ((c1 (string-ref s1 i))
(c2 (string-ref s2 i)))
(cond ((char=? c1 c2)
(if (ctypep c1)
(match-so-far (+ 1 i) ctypep)
(delimited i)))
((ctypep c1)
(if (ctypep c2)
(length-race (+ 1 i) ctypep (char<? c1 c2))
#f))
((ctypep c2) #t)
(else
(let ((ctype1 (ctype c1)))
(cond
((and ctype1 (eq? ctype1 (ctype c2)))
(length-race (+ 1 i) ctype1 (char<? c1 c2)))
(else (char<? c1 c2))))))))))
(define (length-race i ctypep def)
(cond ((>= i l1) (if (>= i l2) def #t))
((>= i l2) #f)
(else
(let ((c1 (string-ref s1 i))
(c2 (string-ref s2 i)))
(cond ((ctypep c1)
(if (ctypep c2)
(length-race (+ 1 i) ctypep def)
#f))
((ctypep c2) #t)
(else def))))))
(define (ctype c1)
(cond
((char-numeric? c1) char-numeric?)
((char-lower-case? c1) char-lower-case?)
((char-upper-case? c1) char-upper-case?)
(else #f)))
(define (delimited i)
(cond ((>= i l1) (not (>= i l2)))
((>= i l2) #f)
(else
(let* ((c1 (string-ref s1 i))
(c2 (string-ref s2 i))
(ctype1 (ctype c1)))
(cond ((char=? c1 c2)
(if ctype1 (match-so-far (+ i 1) ctype1)
(delimited (+ i 1))))
((and ctype1 (eq? ctype1 (ctype c2)))
(length-race (+ 1 i) ctype1 (char<? c1 c2)))
(else (char<? c1 c2)))))))
(delimited 0)))
(define chap:char-incr (- (char->integer #\2) (char->integer #\1)))
(define (chap:inc-string s p)
(let ((c (string-ref s p)))
(cond ((char=? c #\z)
(string-set! s p #\a)
(cond ((zero? p) (string-append "a" s))
((char-lower-case? (string-ref s (+ -1 p)))
(chap:inc-string s (+ -1 p)))
(else
(string-append
(substring s 0 p)
"a"
(substring s p (string-length s))))))
((char=? c #\Z)
(string-set! s p #\A)
(cond ((zero? p) (string-append "A" s))
((char-upper-case? (string-ref s (+ -1 p)))
(chap:inc-string s (+ -1 p)))
(else
(string-append
(substring s 0 p)
"A"
(substring s p (string-length s))))))
((char=? c #\9)
(string-set! s p #\0)
(cond ((zero? p) (string-append "1" s))
((char-numeric? (string-ref s (+ -1 p)))
(chap:inc-string s (+ -1 p)))
(else
(string-append
(substring s 0 p)
"1"
(substring s p (string-length s))))))
((or (char-alphabetic? c) (char-numeric? c))
(string-set! s p (integer->char
(+ chap:char-incr
(char->integer (string-ref s p)))))
s)
(else (slib:error "inc-string error" s p)))))
(define (chap:next-string s)
(do ((i (+ -1 (string-length s)) (+ -1 i)))
((or (negative? i)
(char-numeric? (string-ref s i))
(char-alphabetic? (string-ref s i)))
(if (negative? i) (string-append s "0")
(chap:inc-string (string-copy s) i)))))
;;; testing utilities
;(define (ns s1) (chap:next-string s1))
;(define (ts s1 s2)
; (let ((s< (chap:string<? s1 s2))
; (s> (chap:string<? s2 s1)))
; (cond (s<
; (display s1)
; (display " < ")
; (display s2)
; (newline)))
; (cond (s>
; (display s1)
; (display " > ")
; (display s2)
; (newline)))))
(define (chap:string>? s1 s2) (chap:string<? s2 s1))
(define (chap:string>=? s1 s2) (not (chap:string<? s1 s2)))
(define (chap:string<=? s1 s2) (not (chap:string<? s2 s1)))