Slices, string-search, and trimming left and right
🤖 Generated with [ECA](https://eca.dev) Co-Authored-By: eca-agent <git@eca.dev>
This commit is contained in:
parent
16278c2c92
commit
5924aa27bc
1 changed files with 48 additions and 1 deletions
|
|
@ -1734,6 +1734,8 @@ Characters are written @code{#\a}, @code{#\space}, @code{#\newline}. They can be
|
|||
(str "a" "b" "c") ;; "abc": any number of strings
|
||||
(string-upcase "björn") ;; "BJÖRN"
|
||||
(string-trim " hi ") ;; "hi"
|
||||
(string-trim-left " hi ") ;; "hi "
|
||||
(string-trim-right " hi ") ;; " hi"
|
||||
(string-pad-left "7" 3 #:with #\0) ;; "007"
|
||||
(string-split "a,b,,c" ",") ;; ["a" "b" "" "c"]: a Vec
|
||||
(string-join ["a" "b" "c"] ", ") ;; "a, b, c"
|
||||
|
|
@ -1747,7 +1749,7 @@ All of these compare strings ordinally, byte by byte, which for UTF-8 is the ord
|
|||
|
||||
@subsubsection{Cursors}
|
||||
|
||||
A cursor is a position in a string. It is as cheap as an int, but it always sits on a character boundary, and it can only be moved one character at a time, which is what makes it safe. Every cursor function takes the string as well as the cursor.
|
||||
A cursor is a position in a string. It is as cheap as an int, but it always sits on a character boundary, and it can only be moved one character at a time, which is what makes it safe. Every cursor function takes the string as well as the cursor. Positions are always cursors: nothing takes a byte index, and the searches answer cursors too.
|
||||
|
||||
@codeblock[#:lang "bjolang"]|{
|
||||
(: capitalise (-> string string))
|
||||
|
|
@ -1769,6 +1771,15 @@ A cursor is a position in a string. It is as cheap as an int, but it always sits
|
|||
(None s)))
|
||||
|
||||
(first-word "hello there world") ;; "hello"
|
||||
|
||||
;; string-search finds where a string starts; string-search-backward, the last one.
|
||||
(: extension (-> string string))
|
||||
(defun (extension path)
|
||||
(match (string-search-backward path ".")
|
||||
((Some dot) (substring path (string-cursor-next path dot) (string-cursor-end path)))
|
||||
(None "")))
|
||||
|
||||
(extension "notes.backup.txt") ;; "txt"
|
||||
}|
|
||||
|
||||
The folds walk a string for you, and are usually simpler than a cursor:
|
||||
|
|
@ -1785,6 +1796,42 @@ The folds walk a string for you, and are usually simpler than a cursor:
|
|||
(count-vowels "Hello World") ;; 3
|
||||
}|
|
||||
|
||||
@subsubsection{Slices}
|
||||
|
||||
@code{substring}, @code{string-trim} and @code{string-split} copy the text they answer. A slice is the same text without the copy: a string that shares the bytes of the string it was taken from. Only the forms ending in @code{/slice} make one:
|
||||
|
||||
@codeblock[#:lang "bjolang"]|{
|
||||
(substring/slice s start end)
|
||||
(string-trim/slice s)
|
||||
(string-trim-left/slice s)
|
||||
(string-trim-right/slice s)
|
||||
(string-split/slice s sep)
|
||||
}|
|
||||
|
||||
A slice is a @code{string} like any other. It equals, hashes and orders by its text, so it finds a map key with that text, and it can be passed anywhere a string can. That makes slices the thing to reach for when a scanner cuts many short pieces out of one text and only looks at them:
|
||||
|
||||
@codeblock[#:lang "bjolang"]|{
|
||||
;; "name = Björn; age = 42" into a map, without copying a key or a value
|
||||
;; before it is needed.
|
||||
(: settings (-> string (Map string string)))
|
||||
(defun (settings line)
|
||||
(loop (:for field (string-split/slice line ";"))
|
||||
(:let parts (string-split/slice field "="))
|
||||
(:when (= (vec-length parts) 2))
|
||||
(:acc m (mapping ((string-copy (string-trim/slice (vec-ref parts 0)))
|
||||
. (string-copy (string-trim/slice (vec-ref parts 1))))))
|
||||
=> m))
|
||||
|
||||
(map-ref (settings "name = Björn; age = 42") "age") ;; "42"
|
||||
}|
|
||||
|
||||
Two things are different about a slice:
|
||||
|
||||
@itemlist{
|
||||
@item{@strong{Its cursors are its source's.} A cursor found in a slice, by @code{string-search}, @code{string-index} or a regex, is a position in the string the slice was taken from, and @code{(string-cursor-start sl)} is where the slice begins in it.}
|
||||
@item{@strong{It keeps all of its source alive.} A slice of ten bytes out of a file of a megabyte holds on to the megabyte. That is why the plain forms copy, and why the example copies what it keeps: @code{(string-copy s)} gives a string bytes of its own, and is @code{s} itself when it already has them.}
|
||||
}
|
||||
|
||||
@subsubsection{Building strings}
|
||||
|
||||
Appending strings in a loop copies the whole string every time. Use a string builder instead, or the @code{stringing} collector, which uses one for you:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue