-
Notifications
You must be signed in to change notification settings - Fork 128
Expand file tree
/
Copy pathstring.pxi
More file actions
103 lines (93 loc) · 3.26 KB
/
string.pxi
File metadata and controls
103 lines (93 loc) · 3.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
(ns pixie.string
(:require [pixie.string.internal :as si]))
; reexport native string functions
(def substring si/substring)
(def index-of (comp #(if (not= -1 %) %) si/index-of))
(def split si/split)
(def ends-with? si/ends-with)
(def starts-with? si/starts-with)
(def trim si/trim)
(def triml si/triml)
(def trimr si/trimr)
(def capitalize si/capitalize)
(def lower-case si/lower-case)
(def upper-case si/upper-case)
; TODO: There should be locale-aware variants of these values
(def lower "abcdefghijklmnopqrstuvwxyz")
(def upper "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
(def digits "0123456789")
(def punctuation "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")
(def whitespace (str \space \newline \tab \backspace \formfeed \return))
(def letters (str lower upper))
(def printable (str letters digits punctuation whitespace))
(def hexdigits "0123456789abcdefABCDEF")
(def octdigits "012345678")
(defn replace
"Replace all occurrences of x in s with r."
[s x r]
(let [offset (if (zero? (count x)) (+ 1 (count r)) (count r))]
(loop [start 0
s s]
(if-let [i (index-of s x start)]
(recur (+ i offset) (str (substring s 0 i) r (substring s (+ i (count x)))))
s))))
(defn replace-first
"Replace the first occurrence of x in s with r."
[s x r]
(if-let [i (index-of s x)]
(str (substring s 0 i) r (substring s (+ i (count x))))
s))
(defn join
{:doc "Join the elements of the collection using an optional separator"
:examples [["(require pixie.string :as s)"]
["(s/join [1 2 3])" nil "123"]
["(s/join \", \" [1 2 3])" nil "1, 2, 3"]]}
([coll] (join "" coll))
([separator coll]
(loop [s (seq coll)
res ""]
(cond
(nil? s) res
(nil? (next s)) (str res (first s))
:else (recur (next s) (str res (first s) separator))))))
(defn blank?
"True if s is nil, empty, or contains only whitespace."
[s]
(if s
(let [white (set whitespace)
length (count s)]
(loop [index 0]
(if (= length index)
true
(if (white (nth s index))
(recur (inc index))
false))))
true))
(defmacro interp
; TODO: This might merit special read syntax
{:doc "String interpolation."
:examples [["(require pixie.string :refer [interp])"]
["(interp \"2 plus 2 is $(+ 2 2)$!\")" nil "2 plus 2 is 4!"]
["(let [x \"locals\"] (interp \"You can use arbitrary forms; for example $x$\"))"
nil "You can use arbitrary forms; for example locals"]
["(interp \"$$$$ is the escape for a literal $$\")"
nil "$$ is the escape for a literal $"]
]}
[txt]
(loop [forms [], txt txt]
(cond
(empty? txt) `(str ~@ forms)
(starts-with? txt "$")
(let [pos (or (index-of txt "$" 1)
(throw "Unmatched $ in interp argument!"))
form-str (subs txt 1 pos)
form (if (empty? form-str) "$"
(read-string form-str))
rest-str (subs txt (inc pos))]
(recur (conj forms form) rest-str))
:else
(let [pos (or (index-of txt "$")
(count txt))
form (subs txt 0 pos)
rest-str (subs txt pos)]
(recur (conj forms form) rest-str)))))