string-fun.scm 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. ;;;; string-fun.scm --- string manipulation functions
  2. ;;;;
  3. ;;;; Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
  4. ;;;;
  5. ;;;; This program is free software; you can redistribute it and/or modify
  6. ;;;; it under the terms of the GNU General Public License as published by
  7. ;;;; the Free Software Foundation; either version 2, or (at your option)
  8. ;;;; any later version.
  9. ;;;;
  10. ;;;; This program is distributed in the hope that it will be useful,
  11. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;;;; GNU General Public License for more details.
  14. ;;;;
  15. ;;;; You should have received a copy of the GNU General Public License
  16. ;;;; along with this software; see the file COPYING. If not, write to
  17. ;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  18. ;;;; Boston, MA 02111-1307 USA
  19. ;;;;
  20. (define-module (ice-9 string-fun))
  21. ;;;;
  22. ;;;
  23. ;;; Various string funcitons, particularly those that take
  24. ;;; advantage of the "shared substring" capability.
  25. ;;;
  26. ;;; {String Fun: Dividing Strings Into Fields}
  27. ;;;
  28. ;;; The names of these functions are very regular.
  29. ;;; Here is a grammar of a call to one of these:
  30. ;;;
  31. ;;; <string-function-invocation>
  32. ;;; := (<action>-<seperator-disposition>-<seperator-determination> <seperator-param> <str> <ret>)
  33. ;;;
  34. ;;; <str> = the string
  35. ;;;
  36. ;;; <ret> = The continuation. String functions generally return
  37. ;;; multiple values by passing them to this procedure.
  38. ;;;
  39. ;;; <action> = split
  40. ;;; | separate-fields
  41. ;;;
  42. ;;; "split" means to divide a string into two parts.
  43. ;;; <ret> will be called with two arguments.
  44. ;;;
  45. ;;; "separate-fields" means to divide a string into as many
  46. ;;; parts as possible. <ret> will be called with
  47. ;;; however many fields are found.
  48. ;;;
  49. ;;; <seperator-disposition> = before
  50. ;;; | after
  51. ;;; | discarding
  52. ;;;
  53. ;;; "before" means to leave the seperator attached to
  54. ;;; the beginning of the field to its right.
  55. ;;; "after" means to leave the seperator attached to
  56. ;;; the end of the field to its left.
  57. ;;; "discarding" means to discard seperators.
  58. ;;;
  59. ;;; Other dispositions might be handy. For example, "isolate"
  60. ;;; could mean to treat the separator as a field unto itself.
  61. ;;;
  62. ;;; <seperator-determination> = char
  63. ;;; | predicate
  64. ;;;
  65. ;;; "char" means to use a particular character as field seperator.
  66. ;;; "predicate" means to check each character using a particular predicate.
  67. ;;;
  68. ;;; Other determinations might be handy. For example, "character-set-member".
  69. ;;;
  70. ;;; <seperator-param> = A parameter that completes the meaning of the determinations.
  71. ;;; For example, if the determination is "char", then this parameter
  72. ;;; says which character. If it is "predicate", the parameter is the
  73. ;;; predicate.
  74. ;;;
  75. ;;;
  76. ;;; For example:
  77. ;;;
  78. ;;; (separate-fields-discarding-char #\, "foo, bar, baz, , bat" list)
  79. ;;; => ("foo" " bar" " baz" " " " bat")
  80. ;;;
  81. ;;; (split-after-char #\- 'an-example-of-split list)
  82. ;;; => ("an-" "example-of-split")
  83. ;;;
  84. ;;; As an alternative to using a determination "predicate", or to trying to do anything
  85. ;;; complicated with these functions, consider using regular expressions.
  86. ;;;
  87. (define-public (split-after-char char str ret)
  88. (let ((end (cond
  89. ((string-index str char) => 1+)
  90. (else (string-length str)))))
  91. (ret (make-shared-substring str 0 end)
  92. (make-shared-substring str end))))
  93. (define-public (split-before-char char str ret)
  94. (let ((end (or (string-index str char)
  95. (string-length str))))
  96. (ret (make-shared-substring str 0 end)
  97. (make-shared-substring str end))))
  98. (define-public (split-discarding-char char str ret)
  99. (let ((end (string-index str char)))
  100. (if (not end)
  101. (ret str "")
  102. (ret (make-shared-substring str 0 end)
  103. (make-shared-substring str (1+ end))))))
  104. (define-public (split-after-char-last char str ret)
  105. (let ((end (cond
  106. ((string-rindex str char) => 1+)
  107. (else 0))))
  108. (ret (make-shared-substring str 0 end)
  109. (make-shared-substring str end))))
  110. (define-public (split-before-char-last char str ret)
  111. (let ((end (or (string-rindex str char) 0)))
  112. (ret (make-shared-substring str 0 end)
  113. (make-shared-substring str end))))
  114. (define-public (split-discarding-char-last char str ret)
  115. (let ((end (string-rindex str char)))
  116. (if (not end)
  117. (ret str "")
  118. (ret (make-shared-substring str 0 end)
  119. (make-shared-substring str (1+ end))))))
  120. (define-public (split-before-predicate pred str ret)
  121. (let loop ((n 0))
  122. (cond
  123. ((= n (string-length str)) (ret str ""))
  124. ((not (pred (string-ref str n))) (loop (1+ n)))
  125. (else (ret (make-shared-substring str 0 n)
  126. (make-shared-substring str n))))))
  127. (define-public (split-after-predicate pred str ret)
  128. (let loop ((n 0))
  129. (cond
  130. ((= n (string-length str)) (ret str ""))
  131. ((not (pred (string-ref str n))) (loop (1+ n)))
  132. (else (ret (make-shared-substring str 0 (1+ n))
  133. (make-shared-substring str (1+ n)))))))
  134. (define-public (split-discarding-predicate pred str ret)
  135. (let loop ((n 0))
  136. (cond
  137. ((= n (string-length str)) (ret str ""))
  138. ((not (pred (string-ref str n))) (loop (1+ n)))
  139. (else (ret (make-shared-substring str 0 n)
  140. (make-shared-substring str (1+ n)))))))
  141. (define-public (separate-fields-discarding-char ch str ret)
  142. (let loop ((fields '())
  143. (str str))
  144. (cond
  145. ((string-rindex str ch)
  146. => (lambda (w) (loop (cons (make-shared-substring str (+ 1 w)) fields)
  147. (make-shared-substring str 0 w))))
  148. (else (apply ret str fields)))))
  149. (define-public (separate-fields-after-char ch str ret)
  150. (reverse
  151. (let loop ((fields '())
  152. (str str))
  153. (cond
  154. ((string-index str ch)
  155. => (lambda (w) (loop (cons (make-shared-substring str 0 (+ 1 w)) fields)
  156. (make-shared-substring str (+ 1 w)))))
  157. (else (apply ret str fields))))))
  158. (define-public (separate-fields-before-char ch str ret)
  159. (let loop ((fields '())
  160. (str str))
  161. (cond
  162. ((string-rindex str ch)
  163. => (lambda (w) (loop (cons (make-shared-substring str w) fields)
  164. (make-shared-substring str 0 w))))
  165. (else (apply ret str fields)))))
  166. ;;; {String Fun: String Prefix Predicates}
  167. ;;;
  168. ;;; Very simple:
  169. ;;;
  170. ;;; (define-public ((string-prefix-predicate pred?) prefix str)
  171. ;;; (and (<= (string-length prefix) (string-length str))
  172. ;;; (pred? prefix (make-shared-substring str 0 (string-length prefix)))))
  173. ;;;
  174. ;;; (define-public string-prefix=? (string-prefix-predicate string=?))
  175. ;;;
  176. (define-public ((string-prefix-predicate pred?) prefix str)
  177. (and (<= (string-length prefix) (string-length str))
  178. (pred? prefix (make-shared-substring str 0 (string-length prefix)))))
  179. (define-public string-prefix=? (string-prefix-predicate string=?))
  180. ;;; {String Fun: Strippers}
  181. ;;;
  182. ;;; <stripper> = sans-<removable-part>
  183. ;;;
  184. ;;; <removable-part> = surrounding-whitespace
  185. ;;; | trailing-whitespace
  186. ;;; | leading-whitespace
  187. ;;; | final-newline
  188. ;;;
  189. (define-public (sans-surrounding-whitespace s)
  190. (let ((st 0)
  191. (end (string-length s)))
  192. (while (and (< st (string-length s))
  193. (char-whitespace? (string-ref s st)))
  194. (set! st (1+ st)))
  195. (while (and (< 0 end)
  196. (char-whitespace? (string-ref s (1- end))))
  197. (set! end (1- end)))
  198. (if (< end st)
  199. ""
  200. (make-shared-substring s st end))))
  201. (define-public (sans-trailing-whitespace s)
  202. (let ((st 0)
  203. (end (string-length s)))
  204. (while (and (< 0 end)
  205. (char-whitespace? (string-ref s (1- end))))
  206. (set! end (1- end)))
  207. (if (< end st)
  208. ""
  209. (make-shared-substring s st end))))
  210. (define-public (sans-leading-whitespace s)
  211. (let ((st 0)
  212. (end (string-length s)))
  213. (while (and (< st (string-length s))
  214. (char-whitespace? (string-ref s st)))
  215. (set! st (1+ st)))
  216. (if (< end st)
  217. ""
  218. (make-shared-substring s st end))))
  219. (define-public (sans-final-newline str)
  220. (cond
  221. ((= 0 (string-length str))
  222. str)
  223. ((char=? #\nl (string-ref str (1- (string-length str))))
  224. (make-shared-substring str 0 (1- (string-length str))))
  225. (else str)))
  226. ;;; {String Fun: has-trailing-newline?}
  227. ;;;
  228. (define-public (has-trailing-newline? str)
  229. (and (< 0 (string-length str))
  230. (char=? #\nl (string-ref str (1- (string-length str))))))
  231. ;;; {String Fun: with-regexp-parts}
  232. ;;; This relies on the older, hairier regexp interface, which we don't
  233. ;;; particularly want to implement, and it's not used anywhere, so
  234. ;;; we're just going to drop it for now.
  235. ;;; (define-public (with-regexp-parts regexp fields str return fail)
  236. ;;; (let ((parts (regexec regexp str fields)))
  237. ;;; (if (number? parts)
  238. ;;; (fail parts)
  239. ;;; (apply return parts))))