diff options
| author | 2025-10-09 21:58:43 +0300 | |
|---|---|---|
| committer | 2025-10-09 21:58:43 +0300 | |
| commit | 4da3ad1f569832845b58c3ce35149633a2bb665c (patch) | |
| tree | 5a09a0de66df7ec2e77f0fc9cc68ccbabc190934 /src/strings.lisp | |
| download | ukkoclot-4da3ad1f569832845b58c3ce35149633a2bb665c.tar.gz ukkoclot-4da3ad1f569832845b58c3ce35149633a2bb665c.tar.xz ukkoclot-4da3ad1f569832845b58c3ce35149633a2bb665c.zip | |
Initial commit
Diffstat (limited to 'src/strings.lisp')
| -rw-r--r-- | src/strings.lisp | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/strings.lisp b/src/strings.lisp new file mode 100644 index 0000000..68289aa --- /dev/null +++ b/src/strings.lisp | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | ;; SPDX-License-Identifier: EUPL-1.2 | ||
| 2 | ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> | ||
| 3 | (defpackage :ukkoclot/strings | ||
| 4 | (:use :c2cl :iterate) | ||
| 5 | (:import-from :cl-unicode :general-category) | ||
| 6 | (:export :escape-xml :is-tg-whitespace-str :lisp->snake-case :snake->lisp-case :starts-with :starts-with-ignore-case)) | ||
| 7 | (in-package :ukkoclot/strings) | ||
| 8 | |||
| 9 | ;; These are very inefficient but I don't care until I profile | ||
| 10 | |||
| 11 | (defun escape-xml (str &optional out) | ||
| 12 | (if out | ||
| 13 | (escape-xml% str out) | ||
| 14 | (with-output-to-string (out) | ||
| 15 | (escape-xml% str out)))) | ||
| 16 | |||
| 17 | (defun escape-xml% (str out) | ||
| 18 | (loop for ch across str do | ||
| 19 | (case ch | ||
| 20 | (#\< (write-string "<" out)) | ||
| 21 | (#\> (write-string ">" out)) | ||
| 22 | (#\& (write-string "&" out)) | ||
| 23 | (#\" (write-string """ out)) | ||
| 24 | (t (write-char ch out))))) | ||
| 25 | |||
| 26 | (defun is-tg-whitespace (ch) | ||
| 27 | (let ((gc (general-category ch))) | ||
| 28 | (or (string= gc "Zs") ; Separator, space | ||
| 29 | (string= gc "Zl") ; Separator, line | ||
| 30 | (string= gc "Zp") ; Separator, paragraph | ||
| 31 | (string= gc "Cc") ; Other, control | ||
| 32 | (= (char-code ch) #x2800) ; BRAILLE PATTERN BLANK | ||
| 33 | ))) | ||
| 34 | |||
| 35 | (defun is-tg-whitespace-str (str) | ||
| 36 | (iter (for ch in-string str) | ||
| 37 | (always (is-tg-whitespace ch)))) | ||
| 38 | |||
| 39 | (defun lisp->snake-case (str) | ||
| 40 | (with-output-to-string (out) | ||
| 41 | (loop for ch across str do | ||
| 42 | (case ch | ||
| 43 | (#\- (write-char #\_ out)) | ||
| 44 | (t (write-char ch out)))))) | ||
| 45 | |||
| 46 | (defun snake->lisp-case (str) | ||
| 47 | (with-output-to-string (out) | ||
| 48 | (loop for ch across str do | ||
| 49 | (case ch | ||
| 50 | (#\_ (write-char #\- out)) | ||
| 51 | (t (write-char ch out)))))) | ||
| 52 | |||
| 53 | (defun starts-with (str prefix) | ||
| 54 | (and (> (length str) (length prefix)) | ||
| 55 | (string= str prefix :end1 (length prefix)))) | ||
| 56 | |||
| 57 | (defun starts-with-ignore-case (str prefix) | ||
| 58 | (and (> (length str) (length prefix)) | ||
| 59 | (string-equal str prefix :end1 (length prefix)))) | ||