summaryrefslogtreecommitdiff
path: root/src/strings.lisp
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2025-10-09 21:58:43 +0300
committerGravatar Uko Kokņevičs2025-10-09 21:58:43 +0300
commit4da3ad1f569832845b58c3ce35149633a2bb665c (patch)
tree5a09a0de66df7ec2e77f0fc9cc68ccbabc190934 /src/strings.lisp
downloadukkoclot-4da3ad1f569832845b58c3ce35149633a2bb665c.tar.gz
ukkoclot-4da3ad1f569832845b58c3ce35149633a2bb665c.tar.xz
ukkoclot-4da3ad1f569832845b58c3ce35149633a2bb665c.zip
Initial commit
Diffstat (limited to 'src/strings.lisp')
-rw-r--r--src/strings.lisp59
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 "&lt;" out))
21 (#\> (write-string "&gt;" out))
22 (#\& (write-string "&amp;" out))
23 (#\" (write-string "&quot;" 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))))