4.3 Strings
Strings (Unicode) in The Racket Guide introduces strings.
A string is a fixed-length array of characters.
A string can be mutable or immutable. When an immutable string is provided to a procedure like string-set!, the exn:fail:contract exception is raised. String constants generated by the default reader (see Reading Strings) are immutable, and they are interned in read-syntax mode.
Two strings are equal? when they have the same length and contain the same sequence of characters.
A string can be used as a single-valued sequence (see Sequences). The characters of the string serve as elements of the sequence. See also in-string.
See Reading Strings for information on reading strings and Printing Strings for information on printing strings.
See also: immutable?, symbol->string, bytes->string/utf-8.
4.3.1 String Constructors, Selectors, and Mutators
procedure
(make-string k [char]) → string?
k : exact-nonnegative-integer? char : char? = #\nul
> (make-string 5 #\z) "zzzzz"
> (string #\A #\p #\p #\l #\e) "Apple"
procedure
(string->immutable-string str) → (and/c string? immutable?)
str : string?
procedure
str : string?
> (string-length "Apple") 5
procedure
(string-ref str k) → char?
str : string? k : exact-nonnegative-integer?
> (string-ref "Apple" 0) #\A
procedure
(string-set! str k char) → void?
str : (and/c string? (not/c immutable?)) k : exact-nonnegative-integer? char : char?
> (define s (string #\A #\p #\p #\l #\e)) > (string-set! s 4 #\y) > s "Apply"
procedure
str : string? start : exact-nonnegative-integer? end : exact-nonnegative-integer? = (string-length str)
procedure
(string-copy str) → string?
str : string?
> (define s1 "Yui") > (define pilot (string-copy s1)) > (list s1 pilot) '("Yui" "Yui")
> (for ([i (in-naturals)] [ch '(#\R #\e #\i)]) (string-set! pilot i ch)) > (list s1 pilot) '("Yui" "Rei")
procedure
(string-copy! dest dest-start src [ src-start src-end]) → void? dest : (and/c string? (not/c immutable?)) dest-start : exact-nonnegative-integer? src : string? src-start : exact-nonnegative-integer? = 0 src-end : exact-nonnegative-integer? = (string-length src)
> (define s (string #\A #\p #\p #\l #\e)) > (string-copy! s 4 "y") > (string-copy! s 0 s 3 4) > s "lpply"
procedure
(string-fill! dest char) → void?
dest : (and/c string? (not/c immutable?)) char : char?
> (define s (string #\A #\p #\p #\l #\e)) > (string-fill! s #\q) > s "qqqqq"
procedure
(string-append str ...) → string?
str : string?
> (string-append "Apple" "Banana") "AppleBanana"
procedure
(string->list str) → (listof char?)
str : string?
> (string->list "Apple") '(#\A #\p #\p #\l #\e)
procedure
(list->string lst) → string?
lst : (listof char?)
> (list->string (list #\A #\p #\p #\l #\e)) "Apple"
procedure
(build-string n proc) → string?
n : exact-nonnegative-integer? proc : (exact-nonnegative-integer? . -> . char?)
> (build-string 5 (lambda (i) (integer->char (+ i 97)))) "abcde"
4.3.2 String Comparisons
procedure
(string-ci=? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
> (string-ci=? "Apple" "apple") #t
> (string-ci=? "a" "a" "a") #t
procedure
(string-ci<? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
> (string-ci<? "Apple" "apple") #f
> (string-ci<? "apple" "banana") #t
> (string-ci<? "a" "b" "c") #t
procedure
(string-ci<=? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
> (string-ci<=? "Apple" "apple") #t
> (string-ci<=? "apple" "Apple") #t
> (string-ci<=? "a" "b" "b") #t
procedure
(string-ci>? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
> (string-ci>? "Apple" "apple") #f
> (string-ci>? "banana" "Apple") #t
> (string-ci>? "c" "b" "a") #t
procedure
(string-ci>=? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
> (string-ci>=? "Apple" "apple") #t
> (string-ci>=? "apple" "Apple") #t
> (string-ci>=? "c" "b" "b") #t
4.3.3 String Conversions
procedure
(string-upcase str) → string?
str : string?
> (string-upcase "abc!") "ABC!"
> (string-upcase "Straße") "STRASSE"
procedure
(string-downcase string) → string?
string : string?
> (string-downcase "aBC!") "abc!"
> (string-downcase "Straße") "straße"
> (string-downcase "ΚΑΟΣ") "καος"
> (string-downcase "Σ") "σ"
procedure
(string-titlecase string) → string?
string : string?
> (string-titlecase "aBC twO") "Abc Two"
> (string-titlecase "y2k") "Y2K"
> (string-titlecase "main straße") "Main Straße"
> (string-titlecase "stra ße") "Stra Sse"
procedure
(string-foldcase string) → string?
string : string?
> (string-foldcase "aBC!") "abc!"
> (string-foldcase "Straße") "strasse"
> (string-foldcase "ΚΑΟΣ") "καοσ"
procedure
(string-normalize-nfd string) → string?
string : string?
procedure
(string-normalize-nfkd string) → string?
string : string?
procedure
(string-normalize-nfc string) → string?
string : string?
procedure
(string-normalize-nfkc string) → string?
string : string?
4.3.4 Locale-Specific String Operations
procedure
(string-locale=? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
procedure
(string-locale<? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
procedure
(string-locale>? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
procedure
(string-locale-ci=? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
procedure
(string-locale-ci<? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
procedure
(string-locale-ci>? str1 str2 ...+) → boolean?
str1 : string? str2 : string?
procedure
(string-locale-upcase string) → string?
string : string?
procedure
(string-locale-downcase string) → string?
string : string?
4.3.5 Additional String Functions
(require racket/string) | package: base |
procedure
(string-append* str ... strs) → string?
str : string? strs : (listof string?)
> (string-append* "a" "b" '("c" "d")) "abcd"
> (string-append* (cdr (append* (map (lambda (x) (list ", " x)) '("Alpha" "Beta" "Gamma"))))) "Alpha, Beta, Gamma"
procedure
(string-join strs [ sep #:before-first before-first #:before-last before-last #:after-last after-last]) → string? strs : (listof string?) sep : string? = " " before-first : string? = "" before-last : string? = sep after-last : string? = ""
> (string-join '("one" "two" "three" "four")) "one two three four"
> (string-join '("one" "two" "three" "four") ", ") "one, two, three, four"
> (string-join '("one" "two" "three" "four") " potato ") "one potato two potato three potato four"
> (string-join '("x" "y" "z") ", " #:before-first "Todo: " #:before-last " and " #:after-last ".") "Todo: x, y and z."
procedure
(string-normalize-spaces str [ sep space #:trim? trim? #:repeat? repeat?]) → string? str : string? sep : (or/c string? regexp?) = #px"\\s+" space : string? = " " trim? : any/c = #t repeat? : any/c = #f
> (string-normalize-spaces " foo bar baz \r\n\t") "foo bar baz"
The result of (string-normalize-spaces str sep space) is the same as (string-join (string-split str sep ....) space).
procedure
(string-replace str from to [#:all? all?]) → string?
str : string? from : (or/c string? regexp?) to : string? all? : any/c = #t
By default, all occurrences are replaced, but only the first match is replaced if all? is #f.
> (string-replace "foo bar baz" "bar" "blah") "foo blah baz"
procedure
(string-split str [ sep #:trim? trim? #:repeat? repeat?]) → (listof string?) str : string? sep : (or/c string? regexp?) = #px"\\s+" trim? : any/c = #t repeat? : any/c = #f
Like string-trim, provide sep to use a different separator, and repeat? controls matching repeated sequences.
> (string-split " foo bar baz \r\n\t") '("foo" "bar" "baz")
> (string-split " ") '()
> (string-split " " #:trim? #f) '("" "")
procedure
(string-trim str [ sep #:left? left? #:right? right? #:repeat? repeat?]) → string? str : string? sep : (or/c string? regexp?) = #px"\\s+" left? : any/c = #t right? : any/c = #t repeat? : any/c = #f
Use #:left? #f or #:right? #f to suppress trimming the corresponding side. When repeat? is #f (the default), only one match is removed from each side; when repeat? is true, all initial or trailing matches are trimmed (which is an alternative to using a regular expression sep that contains +).
> (string-trim " foo bar baz \r\n\t") "foo bar baz"
> (string-trim " foo bar baz \r\n\t" " " #:repeat? #t) "foo bar baz \r\n\t"
> (string-trim "aaaxaayaa" "aa") "axaay"
procedure
(non-empty-string? x) → boolean?
x : any/c
Added in version 6.3 of package base.
procedure
(string-contains? s contained) → boolean?
s : string? contained : string?
procedure
(string-prefix? s prefix) → boolean?
s : string? prefix : string?
procedure
(string-suffix? s suffix) → boolean?
s : string? suffix : string?
> (string-prefix? "Racket" "R") #t
> (string-prefix? "Jacket" "R") #f
> (string-suffix? "Racket" "et") #t
> (string-contains? "Racket" "ack") #t
Added in version 6.3 of package base.
4.3.6 Converting Values to Strings
(require racket/format) | package: base |
The racket/format library provides functions for converting Racket values to strings. In addition to features like padding and numeric formatting, the functions have the virtue of being shorter than format (with format string), number->string, or string-append.
procedure
(~a v ... [ #:separator separator #:width width #:max-width max-width #:min-width min-width #:limit-marker limit-marker #:limit-prefix? limit-prefix? #:align align #:pad-string pad-string #:left-pad-string left-pad-string #:right-pad-string right-pad-string]) → string? v : any/c separator : string? = "" width : (or/c exact-nonnegative-integer? #f) = #f
max-width : (or/c exact-nonnegative-integer? +inf.0) = (or width +inf.0) min-width : exact-nonnegative-integer? = (or width 0) limit-marker : string? = "" limit-prefix? : boolean? = #f align : (or/c 'left 'center 'right) = 'left pad-string : non-empty-string? = " " left-pad-string : non-empty-string? = pad-string right-pad-string : non-empty-string? = pad-string
> (~a "north") "north"
> (~a 'south) "south"
> (~a #"east") "east"
> (~a #\w "e" 'st) "west"
> (~a (list "red" 'green #"blue")) "(red green blue)"
> (~a 17) "17"
> (~a #e1e20) "100000000000000000000"
> (~a pi) "3.141592653589793"
> (~a (expt 6.1 87)) "2.1071509386211452e+68"
The ~a function is primarily useful for strings, numbers, and other atomic data. The ~v and ~s functions are better suited to compound data.
Let s be the concatenated string forms of the vs plus separators. If s is longer than max-width characters, it is truncated to exactly max-width characters. If s is shorter than min-width characters, it is padded to exactly min-width characters. Otherwise s is returned unchanged. If min-width is greater than max-width, an exception is raised.
If s is longer than max-width characters, it is truncated and the end of the string is replaced with limit-marker. If limit-marker is longer than max-width, an exception is raised. If limit-prefix? is #t, the beginning of the string is truncated instead of the end.
> (~a "abcde" #:max-width 5) "abcde"
> (~a "abcde" #:max-width 4) "abcd"
> (~a "abcde" #:max-width 4 #:limit-marker "*") "abc*"
> (~a "abcde" #:max-width 4 #:limit-marker "...") "a..."
> (~a "The quick brown fox" #:max-width 15 #:limit-marker "") "The quick brown"
> (~a "The quick brown fox" #:max-width 15 #:limit-marker "...") "The quick br..."
> (~a "The quick brown fox" #:max-width 15 #:limit-marker "..." #:limit-prefix? #f) "The quick br..."
If s is shorter than min-width, it is padded to at least min-width characters. If align is 'left, then only right padding is added; if align is 'right, then only left padding is added; and if align is 'center, then roughly equal amounts of left padding and right padding are added.
Padding is specified as a non-empty string. Left padding consists of left-pad-string repeated in its entirety as many times as possible followed by a prefix of left-pad-string to fill the remaining space. In contrast, right padding consists of a suffix of right-pad-string followed by a number of copies of right-pad-string in its entirety. Thus left padding starts with the start of left-pad-string and right padding ends with the end of right-pad-string.
> (~a "apple" #:min-width 20 #:align 'left) "apple "
> (~a "pear" #:min-width 20 #:align 'left #:right-pad-string " .") "pear . . . . . . . ."
> (~a "plum" #:min-width 20 #:align 'right #:left-pad-string ". ") ". . . . . . . . plum"
> (~a "orange" #:min-width 20 #:align 'center #:left-pad-string "- " #:right-pad-string " -") "- - - -orange- - - -"
Use width to set both max-width and min-width simultaneously, ensuring that the resulting string is exactly width characters long:
> (~a "terse" #:width 6) "terse "
> (~a "loquacious" #:width 6) "loquac"
procedure
(~v v ... [ #:separator separator #:width width #:max-width max-width #:min-width min-width #:limit-marker limit-marker #:limit-prefix? limit-prefix? #:align align #:pad-string pad-string #:left-pad-string left-pad-string #:right-pad-string right-pad-string]) → string? v : any/c separator : string? = " " width : (or/c exact-nonnegative-integer? #f) = #f
max-width : (or/c exact-nonnegative-integer? +inf.0) = (or width +inf.0) min-width : exact-nonnegative-integer? = (or width 0) limit-marker : string? = "..." limit-prefix? : boolean? = #f align : (or/c 'left 'center 'right) = 'left pad-string : non-empty-string? = " " left-pad-string : non-empty-string? = pad-string right-pad-string : non-empty-string? = pad-string
> (~v "north") "\"north\""
> (~v 'south) "'south"
> (~v #"east") "#\"east\""
> (~v #\w) "#\\w"
> (~v (list "red" 'green #"blue")) "'(\"red\" green #\"blue\")"
Use ~v to produce text that talks about Racket values.
> (let ([nums (for/list ([i 10]) i)]) (~a "The even numbers in " (~v nums) " are " (~v (filter even? nums)) ".")) "The even numbers in '(0 1 2 3 4 5 6 7 8 9) are '(0 2 4 6 8)."
procedure
(~s v ... [ #:separator separator #:width width #:max-width max-width #:min-width min-width #:limit-marker limit-marker #:limit-prefix? limit-prefix? #:align align #:pad-string pad-string #:left-pad-string left-pad-string #:right-pad-string right-pad-string]) → string? v : any/c separator : string? = " " width : (or/c exact-nonnegative-integer? #f) = #f
max-width : (or/c exact-nonnegative-integer? +inf.0) = (or width +inf.0) min-width : exact-nonnegative-integer? = (or width 0) limit-marker : string? = "..." limit-prefix? : boolean? = #f align : (or/c 'left 'center 'right) = 'left pad-string : non-empty-string? = " " left-pad-string : non-empty-string? = pad-string right-pad-string : non-empty-string? = pad-string
> (~s "north") "\"north\""
> (~s 'south) "south"
> (~s #"east") "#\"east\""
> (~s #\w) "#\\w"
> (~s (list "red" 'green #"blue")) "(\"red\" green #\"blue\")"
procedure
(~e v ... [ #:separator separator #:width width #:max-width max-width #:min-width min-width #:limit-marker limit-marker #:limit-prefix? limit-prefix? #:align align #:pad-string pad-string #:left-pad-string left-pad-string #:right-pad-string right-pad-string]) → string? v : any/c separator : string? = " " width : (or/c exact-nonnegative-integer? #f) = #f
max-width : (or/c exact-nonnegative-integer? +inf.0) = (or width +inf.0) min-width : exact-nonnegative-integer? = (or width 0) limit-marker : string? = "..." limit-prefix? : boolean? = #f align : (or/c 'left 'center 'right) = 'left pad-string : non-empty-string? = " " left-pad-string : non-empty-string? = pad-string right-pad-string : non-empty-string? = pad-string
> (~e "north") "\"north\""
> (~e 'south) "'south"
> (~e #"east") "#\"east\""
> (~e #\w) "#\\w"
> (~e (list "red" 'green #"blue")) "'(\"red\" green #\"blue\")"
procedure
(~r x [ #:sign sign #:base base #:precision precision #:notation notation #:format-exponent format-exponent #:min-width min-width #:pad-string pad-string]) → string? x : rational?
sign :
(or/c #f '+ '++ 'parens (let ([ind (or/c string? (list/c string? string?))]) (list/c ind ind ind))) = #f
base : (or/c (integer-in 2 36) (list/c 'up (integer-in 2 36))) = 10
precision :
(or/c exact-nonnegative-integer? (list/c '= exact-nonnegative-integer?)) = 6
notation :
(or/c 'positional 'exponential (-> rational? (or/c 'positional 'exponential))) = 'positional
format-exponent : (or/c #f string? (-> exact-integer? string?)) = #f min-width : exact-positive-integer? = 1 pad-string : non-empty-string? = " "
The optional arguments control number formatting:
notation —
determines whether the number is printed in positional or exponential notation. If notation is a function, it is applied to x to get the notation to be used. Examples:precision —
controls the number of digits after the decimal point (or more accurately, the radix point). When x is formatted in exponential form, precision applies to the significand. If precision is a natural number, then up to precision digits are displayed, but trailing zeroes are dropped, and if all digits after the decimal point are dropped the decimal point is also dropped. If precision is (list '= digits), then exactly digits digits after the decimal point are used, and the decimal point is never dropped.
Examples:min-width —
if x would normally be printed with fewer than min-width digits (including the decimal point but not including the sign indicator), the digits are left-padded using pad-string. Examples:pad-string —
specifies the string used to pad the number to at least min-width characters (not including the sign indicator). The padding is placed between the sign and the normal digits of x. Examples:- sign —
controls how the sign of the number is indicated: If sign is #f (the default), no sign output is generated if x is either positive or zero, and a minus sign is prefixed if x is negative.
Example:If sign is '+, no sign output is generated if x is zero, a plus sign is prefixed if x is positive, and a minus sign is prefixed if x is negative.
Example:If sign is '++, a plus sign is prefixed if x is zero or positive, and a minus sign is prefixed if x is negative.
Example:If sign is 'parens, no sign output is generated if x is zero or positive, and the number is enclosed in parentheses if x is negative.
Example:If sign is (list pos-ind zero-ind neg-ind), then pos-ind, zero-ind, and neg-ind are used to indicate positive, zero, and negative numbers, respectively. Each indicator is either a string to be used as a prefix or a list containing two strings: a prefix and a suffix.
Example:> (let ([sign-table '(("" " up") "an even " ("" " down"))]) (for/list ([x '(17 0 -42)]) (~r x #:sign sign-table))) '("17 up" "an even 0" "42 down")
The default behavior is equivalent to '("" "" "-"); the 'parens mode is equivalent to '("" "" ("(" ")")).
base —
controls the base that x is formatted in. If base is a number greater than 10, then lower-case letters are used. If base is (list 'up base*) and base* is greater than 10, then upper-case letters are used. Examples:format-exponent —
determines how the exponent is displayed. If format-exponent is a string, the exponent is displayed with an explicit sign (as with a sign of '++) and at least two digits, separated from the significand by the “exponent marker” format-exponent:
> (~r 1234 #:notation 'exponential #:format-exponent "E") "1.234E+03"
If format-exponent is #f, the “exponent marker” is "e" if base is 10 and a string involving base otherwise:
> (~r 1234 #:notation 'exponential) "1.234e+03"
> (~r 1234 #:notation 'exponential #:base 8) "2.322*8^+03"
If format-exponent is a procedure, it is applied to the exponent and the resulting string is appended to the significand:
> (~r 1234 #:notation 'exponential #:format-exponent (lambda (e) (format "E~a" e))) "1.234E3"
procedure
(~.a v ... [ #:separator separator #:width width #:max-width max-width #:min-width min-width #:limit-marker limit-marker #:limit-prefix? limit-prefix? #:align align #:pad-string pad-string #:left-pad-string left-pad-string #:right-pad-string right-pad-string]) → string? v : any/c separator : string? = "" width : (or/c exact-nonnegative-integer? #f) = #f
max-width : (or/c exact-nonnegative-integer? +inf.0) = (or width +inf.0) min-width : exact-nonnegative-integer? = (or width 0) limit-marker : string? = "" limit-prefix? : boolean? = #f align : (or/c 'left 'center 'right) = 'left pad-string : non-empty-string? = " " left-pad-string : non-empty-string? = pad-string right-pad-string : non-empty-string? = pad-string
procedure
(~.v v ... [ #:separator separator #:width width #:max-width max-width #:min-width min-width #:limit-marker limit-marker #:limit-prefix? limit-prefix? #:align align #:pad-string pad-string #:left-pad-string left-pad-string #:right-pad-string right-pad-string]) → string? v : any/c separator : string? = " " width : (or/c exact-nonnegative-integer? #f) = #f
max-width : (or/c exact-nonnegative-integer? +inf.0) = (or width +inf.0) min-width : exact-nonnegative-integer? = (or width 0) limit-marker : string? = "..." limit-prefix? : boolean? = #f align : (or/c 'left 'center 'right) = 'left pad-string : non-empty-string? = " " left-pad-string : non-empty-string? = pad-string right-pad-string : non-empty-string? = pad-string
procedure
(~.s v ... [ #:separator separator #:width width #:max-width max-width #:min-width min-width #:limit-marker limit-marker #:limit-prefix? limit-prefix? #:align align #:pad-string pad-string #:left-pad-string left-pad-string #:right-pad-string right-pad-string]) → string? v : any/c separator : string? = " " width : (or/c exact-nonnegative-integer? #f) = #f
max-width : (or/c exact-nonnegative-integer? +inf.0) = (or width +inf.0) min-width : exact-nonnegative-integer? = (or width 0) limit-marker : string? = "..." limit-prefix? : boolean? = #f align : (or/c 'left 'center 'right) = 'left pad-string : non-empty-string? = " " left-pad-string : non-empty-string? = pad-string right-pad-string : non-empty-string? = pad-string