|
8 | 8 |
|
9 | 9 | (ns ^{:doc "Clojure String utilities |
10 | 10 |
|
11 | | -clojure.string adheres to the following design principles: |
| 11 | +It is poor form to (:use clojure.string). Instead, use require |
| 12 | +with :as to specify a prefix, e.g. |
| 13 | +
|
| 14 | +(ns your.namespace.here |
| 15 | + (:require '[clojure.string :as str])) |
| 16 | +
|
| 17 | +Design notes for clojure.string: |
12 | 18 |
|
13 | 19 | 1. Strings are objects (as opposed to sequences). As such, the |
14 | 20 | string being manipulated is the first argument to a function; |
15 | | - passing nil will result in a NullPointerException. If you |
16 | | - want sequence-y behavior instead, use a sequence. |
| 21 | + passing nil will result in a NullPointerException unless |
| 22 | + documented otherwise. If you want sequence-y behavior instead, |
| 23 | + use a sequence. |
17 | 24 |
|
18 | 25 | 2. Functions are generally not lazy, and call straight to host |
19 | 26 | methods where those are available and efficient. |
20 | 27 |
|
21 | | -3. When a function is documented to accept a string argument, it |
| 28 | +3. Functions take advantage of String implementation details to |
| 29 | + write high-performing loop/recurs instead of using higher-order |
| 30 | + functions. (This is not idiomatic in general-purpose application |
| 31 | + code.) |
| 32 | +
|
| 33 | +4. When a function is documented to accept a string argument, it |
22 | 34 | will take any implementation of the correct *interface* on the |
23 | 35 | host platform. In Java, this is CharSequence, which is more |
24 | 36 | general than String. In ordinary usage you will almost always |
@@ -66,7 +78,7 @@ clojure.string adheres to the following design principles: |
66 | 78 | (instance? CharSequence match) (.replace s ^CharSequence match ^CharSequence replacement) |
67 | 79 | (instance? Pattern match) (if (instance? CharSequence replacement) |
68 | 80 | (.replaceAll (re-matcher ^Pattern match s) |
69 | | - (.toString replacement)) |
| 81 | + (.toString ^CharSequence replacement)) |
70 | 82 | (replace-by s match replacement)) |
71 | 83 | :else (throw (IllegalArgumentException. (str "Invalid match arg: " match)))))) |
72 | 84 |
|
@@ -163,6 +175,12 @@ clojure.string adheres to the following design principles: |
163 | 175 | ([ ^CharSequence s ^Pattern re limit] |
164 | 176 | (LazilyPersistentVector/createOwning (.split re s limit)))) |
165 | 177 |
|
| 178 | +(defn split-lines |
| 179 | + "Splits s on \\n or \\r\\n." |
| 180 | + {:added "1.2"} |
| 181 | + [^CharSequence s] |
| 182 | + (split s #"\r?\n")) |
| 183 | + |
166 | 184 | (defn ^String trim |
167 | 185 | "Removes whitespace from both ends of string." |
168 | 186 | {:added "1.2"} |
@@ -204,4 +222,33 @@ clojure.string adheres to the following design principles: |
204 | 222 | (recur (dec index)) |
205 | 223 | (.. s (subSequence 0 index) toString)))))) |
206 | 224 |
|
207 | | - |
| 225 | +(defn blank? |
| 226 | + "True if s is nil, empty, or contains only whitespace." |
| 227 | + {:added "1.2"} |
| 228 | + [^CharSequence s] |
| 229 | + (if s |
| 230 | + (loop [index (int 0)] |
| 231 | + (if (= (.length s) index) |
| 232 | + true |
| 233 | + (if (Character/isWhitespace (.charAt s index)) |
| 234 | + (recur (inc index)) |
| 235 | + false))) |
| 236 | + true)) |
| 237 | + |
| 238 | +(defn ^String escape |
| 239 | + "Return a new string, using cmap to escape each character ch |
| 240 | + from s as follows: |
| 241 | + |
| 242 | + If (cmap ch) is nil, append ch to the new string. |
| 243 | + If (cmap ch) is non-nil, append (str (cmap ch)) instead." |
| 244 | + {:added "1.2"} |
| 245 | + [^CharSequence s cmap] |
| 246 | + (loop [index (int 0) |
| 247 | + buffer (StringBuilder. (.length s))] |
| 248 | + (if (= (.length s) index) |
| 249 | + (.toString buffer) |
| 250 | + (let [ch (.charAt s index)] |
| 251 | + (if-let [replacement (cmap ch)] |
| 252 | + (.append buffer replacement) |
| 253 | + (.append buffer ch)) |
| 254 | + (recur (inc index) buffer))))) |
0 commit comments