Packages
gleam_stdlib
0.10.0
1.0.3
1.0.2
1.0.1
1.0.0
0.71.0
0.70.0
0.69.0
0.68.1
0.68.0
0.67.1
0.67.0
0.65.0
0.64.0
0.63.2
0.63.1
0.63.0
0.62.1
0.62.0
0.61.0
0.60.0
0.59.0
0.58.0
0.57.0
0.56.0
0.55.0
0.54.0
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.1
0.35.0
0.34.0
0.33.1
0.33.0
0.32.1
0.32.0
0.31.0
0.30.2
0.30.1
0.30.0
0.29.2
0.29.1
0.29.0
0.28.2
0.28.1
0.28.0
0.27.0
0.26.1
0.26.0
0.25.0
0.24.0
0.23.0
0.22.3
0.22.2
0.22.1
0.22.0
0.21.0
0.20.0
0.19.3
0.19.2
0.19.1
0.19.0
0.18.1
0.18.0
0.18.0-rc1
0.17.1
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.1
0.10.0
0.9.0
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.4.0-rc1
0.3.1
0.3.0
0.2.0
retired
A standard library for the Gleam programming language
Current section
Files
Jump to
Current section
Files
src/gleam/string.gleam
//// Strings in Gleam are UTF-8 binaries. They can be written in your code a
//// text surrounded by `"double quotes"`.
import gleam/string_builder
import gleam/dynamic.{Dynamic}
import gleam/list
import gleam/order
import gleam/result
pub type String =
String
/// A UtfCodepoint is the integer representation of a valid UTF codepoint
pub type UtfCodepoint =
UtfCodepoint
/// Determine if a string is empty.
///
/// ## Examples
///
/// > is_empty("")
/// True
///
/// > is_empty("the world")
/// False
///
pub fn is_empty(str: String) -> Bool {
str == ""
}
/// Get the number of grapheme clusters in a given string.
///
/// This function has to iterate across the whole string to count the number of
/// graphemes, so it runs in linear time.
///
/// ## Examples
///
/// > length("Gleam")
/// 5
///
/// > length("ß↑e̊")
/// 3
///
/// > length("")
/// 0
///
pub external fn length(String) -> Int =
"string" "length"
///
/// Reverse a string.
///
/// This function has to iterate across the whole string so it runs in linear
/// time.
///
/// ## Examples
///
/// > reverse("stressed")
/// "desserts"
///
pub fn reverse(string: String) -> String {
string
|> string_builder.from_string
|> string_builder.reverse
|> string_builder.to_string
}
/// Create a new string by replacing all occurrences of a given substring.
///
/// ## Examples
///
/// > replace("www.example.com", each: ".", with: "-")
/// "www-example-com"
///
/// > replace("a,b,c,d,e", each: ",", with: "/")
/// "a/b/c/d/e"
///
pub fn replace(
in string: String,
each pattern: String,
with substitute: String,
) -> String {
string
|> string_builder.from_string
|> string_builder.replace(each: pattern, with: substitute)
|> string_builder.to_string
}
/// Create a new string with all the graphemes in the input string converted to
/// lowercase.
///
/// Useful for case-insensitive comparisons.
///
/// ## Examples
///
/// > lowercase("X-FILES")
/// "x-files"
///
pub external fn lowercase(String) -> String =
"string" "lowercase"
/// Create a new string with all the graphemes in the input string converted to
/// uppercase.
///
/// Useful for case-insensitive comparisons and VIRTUAL YELLING.
///
/// ## Examples
///
/// > uppercase("skinner")
/// "SKINNER"
///
pub external fn uppercase(String) -> String =
"string" "uppercase"
/// Compares two strings to see which is "larger" by comparing their graphemes.
///
/// This does not compare the size or length of the given strings.
///
/// ## Examples
///
/// > compare("Anthony", "Anthony")
/// order.Eq
///
/// > compare("A", "B")
/// order.Gt
///
pub external fn compare(String, String) -> order.Order =
"gleam_stdlib" "compare_strings"
external fn erl_slice(String, Int, Int) -> String =
"string" "slice"
/// Take a substring given a start and end Grapheme indexes. Negative indexes
/// are taken starting from the *end* of the list.
///
/// ## Examples
/// > slice(from: "gleam", at_index: 1, length: 2)
/// "le"
///
/// > slice(from: "gleam", at_index: 1, length: 10)
/// "leam"
///
/// > slice(from: "gleam", at_index: 10, length: 3)
/// ""
///
/// > slice(from: "gleam", at_index: -2, length: 2)
/// "am"
///
/// > slice(from: "gleam", at_index: -12, length: 2)
/// ""
///
pub fn slice(
from string: String,
at_index idx: Int,
length len: Int,
) -> String {
case len < 0 {
True -> ""
False -> case idx < 0 {
True -> {
let translated_idx = length(string) + idx
case translated_idx < 0 {
True -> ""
False -> erl_slice(string, translated_idx, len)
}
}
False -> erl_slice(string, idx, len)
}
}
}
/// Drop *n* Graphemes from the left side of a string.
///
/// ## Examples
/// > drop_left(from: "The Lone Gunmen", up_to: 2)
/// "e Lone Gunmen"
///
pub fn drop_left(from string: String, up_to num_graphemes: Int) -> String {
case num_graphemes < 0 {
True -> string
False -> slice(string, num_graphemes, length(string) - num_graphemes)
}
}
/// Drop *n* Graphemes from the right side of a string.
///
/// ## Examples
/// > drop_right(from: "Cigarette Smoking Man", up_to: 2)
/// "Cigarette Smoking M"
///
pub fn drop_right(from string: String, up_to num_graphemes: Int) -> String {
case num_graphemes < 0 {
True -> string
False -> slice(string, 0, length(string) - num_graphemes)
}
}
external fn erl_contains(String, String) -> Dynamic =
"string" "find"
/// Check if the first string contains the second.
///
/// ## Examples
///
/// > contains(does: "theory", contain: "ory")
/// True
///
/// > contains(does: "theory", contain: "the")
/// True
///
/// > contains(does: "theory", contain: "THE")
/// False
///
pub fn contains(does haystack: String, contain needle: String) -> Bool {
haystack
|> erl_contains(needle)
|> dynamic.atom
|> result.is_error
}
/// See if the first string starts with the second one.
///
/// ## Examples
///
/// > starts_with("theory", "ory")
/// False
///
pub external fn starts_with(String, String) -> Bool =
"gleam_stdlib" "string_starts_with"
/// See if the first string ends with the second one.
///
/// ## Examples
///
/// > ends_with("theory", "ory")
/// True
///
pub external fn ends_with(String, String) -> Bool =
"gleam_stdlib" "string_ends_with"
/// Create a list of strings by splitting a given string on a given substring.
///
/// ## Examples
///
/// > split("home/gleam/desktop/", on: "/")
/// ["home", "gleam", "desktop", ""]
///
pub fn split(x: String, on substring: String) -> List(String) {
x
|> string_builder.from_string
|> string_builder.split(on: substring)
|> list.map(with: string_builder.to_string)
}
external fn erl_split(String, String) -> List(String) =
"string" "split"
/// Splits a string a single time on the given substring.
///
/// Returns an error if substring not present.
///
/// ## Examples
///
/// > split_once("home/gleam/desktop/", on: "/")
/// Ok(tuple("home", "gleam/desktop/"))
///
/// > split_once("home/gleam/desktop/", on: "?")
/// Error(Nil)
///
pub fn split_once(
x: String,
on substring: String,
) -> Result(tuple(String, String), Nil) {
case erl_split(x, substring) {
[first, rest] -> Ok(tuple(first, rest))
_ -> Error(Nil)
}
}
/// Create a new string by joining two strings together.
///
/// This function copies both strings and runs in linear time. If you find
/// yourself joining strings frequently consider using the [string_builder](../iodata)
/// module as it can append strings much faster!
///
/// ## Examples
///
/// > append(to: "butter", suffix: "fly")
/// "butterfly"
///
pub fn append(to first: String, suffix second: String) -> String {
first
|> string_builder.from_string
|> string_builder.append(second)
|> string_builder.to_string
}
/// Create a new string by joining many strings together.
///
/// This function copies both strings and runs in linear time. If you find
/// yourself joining strings frequently consider using the [string_builder](../iodata)
/// module as it can append strings much faster!
///
/// ## Examples
///
/// > concat(["never", "the", "less"])
/// "nevertheless"
///
pub fn concat(strings: List(String)) -> String {
strings
|> string_builder.from_strings
|> string_builder.to_string
}
fn repeat_help(chunk: String, result: List(String), repeats: Int) -> String {
case repeats <= 0 {
True -> concat(result)
False -> repeat_help(chunk, [chunk, ..result], repeats - 1)
}
}
/// Create a new string by repeating a string a given number of times.
///
/// This function runs in linear time.
///
/// ## Examples
///
/// > repeat("ha", times: 3)
/// "hahaha"
///
pub fn repeat(string: String, times times: Int) -> String {
repeat_help(string, [], times)
}
/// Join many strings together with a given separator.
///
/// This function runs in linear time.
///
/// ## Examples
///
/// > join(["home","evan","Desktop"], with: "/")
/// "home/evan/Desktop"
///
pub fn join(strings: List(String), with separator: String) -> String {
strings
|> list.intersperse(with: separator)
|> string_builder.from_strings
|> string_builder.to_string
}
type Direction {
Leading
Trailing
Both
}
external fn erl_pad(String, Int, Direction, String) -> String =
"gleam_stdlib" "string_pad"
/// Pad a string on the left until it has at least given number of Graphemes.
///
/// ## Examples
///
/// > pad_left("121", to: 5, with: ".")
/// "..121"
///
/// > pad_left("121", to: 3, with: ".")
/// "121"
///
/// > pad_left("121", to: 2, with: ".")
/// "121"
///
pub fn pad_left(string: String, to length: Int, with pad_string: String) {
erl_pad(string, length, Leading, pad_string)
}
/// Pad a string on the right until it has a given length.
///
/// ## Examples
///
/// > pad_right("121", to: 5, with: ".")
/// "121.."
///
/// > pad_right("121", to: 3, with: ".")
/// "121"
///
/// > pad_right("121", to: 2, with: ".")
/// "121"
///
pub fn pad_right(string: String, to length: Int, with pad_string: String) {
erl_pad(string, length, Trailing, pad_string)
}
external fn erl_trim(String, Direction) -> String =
"string" "trim"
/// Get rid of whitespace on both sides of a String.
///
/// ## Examples
///
/// > trim(" hats \n")
/// "hats"
///
pub fn trim(string: String) -> String {
erl_trim(string, Both)
}
/// Get rid of whitespace on the left of a String.
///
/// ## Examples
///
/// > trim_left(" hats \n")
/// "hats \n"
///
pub fn trim_left(string: String) -> String {
erl_trim(string, Leading)
}
/// Get rid of whitespace on the right of a String.
///
/// ## Examples
///
/// > trim_right(" hats \n")
/// " hats"
///
pub fn trim_right(string: String) -> String {
erl_trim(string, Trailing)
}
/// Split a non-empty string into its head and tail. This lets you
/// pattern match on strings exactly as you would with lists.
///
/// ## Examples
/// > pop_grapheme("gleam")
/// Ok(tuple("g", "leam"))
///
/// > pop_grapheme("")
/// Error(Nil)
///
pub external fn pop_grapheme(
string: String,
) -> Result(tuple(String, String), Nil) =
"gleam_stdlib" "string_pop_grapheme"
/// Convert a string to a list of Graphemes.
///
/// > to_graphemes("abc")
/// ["a", "b", "c"]
///
pub fn to_graphemes(string: String) -> List(String) {
case pop_grapheme(string) {
Ok(tuple(grapheme, rest)) -> [grapheme, ..to_graphemes(rest)]
_ -> []
}
}
external fn int_to_utf_codepoint(Int) -> UtfCodepoint =
"gleam_stdlib" "identity"
/// Convert an integer to a UtfCodepoint
///
/// Returns an error if the integer does not represent a valid UTF codepoint.
///
pub fn utf_codepoint(value: Int) -> Result(UtfCodepoint, Nil) {
case value {
i if i > 1114111 -> Error(Nil)
i if i == 65534 -> Error(Nil)
i if i == 65535 -> Error(Nil)
i if i >= 55296 && i <= 57343 -> Error(Nil)
i -> Ok(int_to_utf_codepoint(i))
}
}