std.string

BoolLiteral

Contract for a string representation of a boolean, namely true or false.

Examples

("true" | std.string.BoolLiteral) =>
  "true"
("hello" | std.string.BoolLiteral) =>
  error
(true | std.string.BoolLiteral) =>
  error

Character

Contract for a character, i.e. a string of length 1.

Examples

("e" | std.string.Character)
  => "e"
("#" | std.string.Character)
  => "#"
("" | std.string.Character)
  => error
(1 | std.string.Character)
  => error

characters : String -> Array String

Separates a string into its individual Unicode extended grapheme clusters.

Examples

std.string.characters "Hello"
  => [ "H", "e", "l", "l", "o" ]

contains : String -> String -> Bool

Checks if the first string is part of the second string.

Note that this function returns false if the sought string exists entirely inside or straddles Unicode extended grapheme clusters.

Examples

std.string.contains "cde" "abcdef"
  => true
std.string.contains "" "abcdef"
  => true
std.string.contains "ghj" "abcdef"
  => false

find : String -> String -> { matched : String, index : Number, groups : Array String }

find regex string looks for matches of regexp in string. Returns the part of string that matched, the index of the first character that was part of the match in string, and an array of all capture groups if there were any.

If there is no match, find returns {matched = "", index = -1, groups = []}.

Note: this function ignores any match where either the match itself, or one of its capture groups, begin or end in the middle of a Unicode extended grapheme cluster.

Examples

std.string.find "^(\\d).*(\\d).*(\\d).*$" "5 apples, 6 pears and 0 grapes"
  => { matched = "5 apples, 6 pears and 0 grapes", index = 0, groups = [ "5", "6", "0" ] }
std.string.find "3" "01234"
  => { matched = "3", index = 3, groups = [ ] }

Performance

Note that this function may perform better by sharing its partial application between multiple calls, because in this case the underlying regular expression will only be compiled once (see the documentation of std.string.is_match for more details).


find_all : String -> String -> Array { matched : String, index : Number, groups : Array String }

find_all regex string looks for all matches of regexp in string. For each match, it returns the part of string that matched, the index of the first character that was part of the match in string, and an array of all capture groups if there were any. Thus the return type is an array of the return type of std.string.find.

If there is no match, find returns an empty array: [].

Note: this function ignores any match where either the match itself, or one of its capture groups, begin or end in the middle of a Unicode extended grapheme cluster.

Examples

std.string.find_all "(\\d) (\\w+)" "5 apples, 6 pears and 0 grapes"
  => [
    { groups = [ "5", "apples" ], index = 0, matched = "5 apples", },
    { groups = [ "6", "pears" ], index = 10, matched = "6 pears", },
    { groups = [ "0", "grapes" ], index = 22, matched = "0 grapes", }
  ]
std.string.find_all "2" "123 123 123"
  => [
    { groups = [  ], index = 1, matched = "2", },
    { groups = [  ], index = 5, matched = "2", },
    { groups = [  ], index = 9, matched = "2", }
  ]

Performance

Note that this function may perform better by sharing its partial application between multiple calls, because in this case the underlying regular expression will only be compiled once (see the documentation of std.string.is_match for more details).


from | Stringable -> String

Converts a stringable value to its string representation. Same as std.to_string.

Examples

std.string.from 42
  => "42"
std.string.from 'Foo
  => "Foo"
std.string.from null
  => "null"
std.string.from {value = 0}
  => error

from_bool | Bool -> String

Converts a boolean value to its string representation.

Examples

std.string.from_bool true
  => "true"

from_enum | forall a. [| ; a |] -> String

from_enum | std.enum.Tag -> Dyn

Converts an enum variant to its string representation.

Examples

std.string.from_enum 'MyEnum
  => "MyEnum"

from_number | Number -> String

Converts a number to its string representation.

Examples

std.string.from_number 42
  => "42"

is_match : String -> String -> Bool

is_match regex string checks if string matches regex.

Note: this function only returns true when the regex match does not begin or end in the middle of a Unicode extended grapheme cluster. For example, searching for "❤️" within the string "👨‍❤️‍💋‍👨" will return false, as the heart codepoint is contained in the larger extended grapheme cluster.

Examples

std.string.is_match "^\\d+$" "123"
  => true
std.string.is_match "\\d{4}" "123"
  => false

Performance

When checking multiple strings against a common regular expression, it is advantageous to store a partially applied version of this function. This partial evaluation will store a compiled version of the regular expression and prevent recompilation at each call site.

For example, in the following program, the whole call to std.string.is_match "[0-9]*\\.?[0-9]+ x" is re-evaluated at each invocation of is_number. The regexp will be compiled 3 times in total:

let is_number = fun x =>
  std.string.is_match "[0-9]*\\.?[0-9]+" x
in
["0", "42", "0.5"]
|> std.array.all is_number
  => true

On the other hand, in the version below, the partial application of std.string.is_match "[0-9]*\\.?[0-9]+" is evaluated once, returning a function capturing the compiled regexp. The regexp will only be compiled once and for all:

let is_number' = std.string.is_match "[0-9]*\\.?[0-9]+" in
["0", "42", "0.5"]
|> std.array.all is_number'
  => true

join : String -> Array String -> String

Joins an array of strings with a given separator.

Examples

std.string.join ", " [ "Hello", "World!" ]
  => "Hello, World!"
std.string.join ";" ["I'm alone"]
  => "I'm alone"
std.string.join ", " []
  => ""

length : String -> Number

Returns the length of the string, as measured by the number of Unicode extended grapheme clusters.

Generally speaking, this gives the number of "visible" glyphs in the string.

Warning: because length works on Unicode grapheme clusters, some seemingly intuitive invariants might not hold. In particular, it isn't always true that length (s1 ++ s2) is equal to length s1 + length s2.

Examples

std.string.length "" =>
  => 0
std.string.length "hi" =>
  => 2
std.string.length "四字熟語" =>
  => 4
std.string.length "👨🏾‍❤️‍💋‍👨🏻" =>
  => 1

lowercase : String -> String

Returns the lowercase version of a string. Unicode extended grapheme clusters without a lowercase version are left untouched.

Examples

std.string.lowercase "A"
  => "a"
std.string.lowercase "Æ"
  => "æ"
std.string.lowercase "HELLO.WORLD"
  => "hello.world"

NonEmpty

Contract for a non-empty string.

Examples

("" | std.string.NonEmpty)
  => error
("hi!" | std.string.NonEmpty)
  => "hi!"
(42 | std.string.NonEmpty)
  => error

NumberLiteral

Contract for a string representation of a numerical value.

Examples

("+1.2" | std.string.NumberLiteral) =>
  "+1.2"
("5" | std.string.NumberLiteral) =>
  "5"
(42 | std.string.NumberLiteral) =>
  error

replace : String -> String -> String -> String

replace sub repl str replaces every occurrence of sub in str with repl.

Note that this function will not replace sub if it exists within a larger unicode extended grapheme cluster.

Examples

std.string.replace "cd" "   " "abcdef"
  => "ab   ef"
std.string.replace "" "A" "abcdef"
  => "AaAbAcAdAeAfA"

replace_regex : String -> String -> String -> String

replace_regex regex repl string replaces every match of regex in string with repl.

Note: this function will only replace matches which start & end on the boundary of Unicode extended grapheme clusters. For example, replace_regex "❤️" "_" "👨‍❤️‍💋‍👨" will return "👨‍❤️‍💋‍👨", since the heart codepoint occurs within the larger emoji grapheme cluster.

Examples

std.string.replace_regex "l+." "j" "Hello!"
  => "Hej!"
std.string.replace_regex "\\d+" "\"a\" is not" "This 37 is a number."
  "This \"a\" is not a number."

split : String -> String -> Array String

Splits a string based on a separator string.

Note that this function never splits up Unicode extended grapheme clusters, even in cases where the sought value exists within one.

Examples

std.string.split "," "1,2,3"
  => [ "1", "2", "3" ]
std.string.split "." "1,2,3"
  => [ "1,2,3" ]

Stringable

Enforces that the value is convertible to a string via std.to_string or std.string.from. Accepted values are:

  • Numbers
  • Booleans
  • Strings
  • Enum tags
  • null

For string representations of more complex values, see std.serialize.

Examples

('Foo | std.string.Stringable)
  => 'Foo
(false | std.string.Stringable)
  => false
("bar" ++ "foo" | std.string.Stringable)
  => "barfoo"
({foo = "baz"} | std.string.Stringable)
  => error

substring : Number -> Number -> String -> String

substring start end str takes the slice of str from start (included) to end (excluded).

The index arguments are the indices of Unicode extended grapheme clusters rather than codepoints.

Preconditions

In substring start end str, start and end must be positive integers such that 0 <= start <= end <= std.array.length value.

Examples

std.string.substring 3 5 "abcdef" =>
  "de"
std.string.substring 3 10 "abcdef" =>
  error
std.string.substring (-3) 4 "abcdef" =>
  error

to_bool : String -> Bool

to_bool | BoolLiteral -> Dyn

Converts a representation of a boolean (either true or false) to that boolean.

Examples

std.string.to_bool "true"
  => true
std.string.to_bool "false"
  => false

to_enum | String -> std.enum.Tag

Converts a string to an enum tag.

Examples

std.string.to_enum "Hello"
  => 'Hello
std.string.to_enum "hey,there!"
  => '"hey,there!"

to_number : String -> Number

to_number | NumberLiteral -> Dyn

Converts a string that represents a number to that number.

Examples

std.string.to_number "123"
  => 123

trim : String -> String

Trims whitespace from the start and end of a string.

Examples

std.string.trim " hi  "
  => "hi"
std.string.trim "1   2   3   "
  => "1   2   3"

uppercase : String -> String

Returns the uppercase version of a string. Unicode extended grapheme clusters without an uppercase version are left untouched.

Examples

std.string.uppercase "a"
  => "A"
std.string.uppercase "æ"
  => "Æ"
std.string.uppercase "hello.world"
  => "HELLO.WORLD"