std.string.String
Atomictype pub builtin StringAn UTF-8 encoded and immutable string type.
Static methods
from_pointer
Show source codeHide source code
fn pub static from_pointer(pointer: Pointer[UInt8]) -> String {
if pointer as Int == 0 { return '' }
from_primitive(inko_string_from_pointer(pointer))
}fn pub static from_pointer(pointer: Pointer[UInt8]) -> StringReturns a String created from the given NULL terminated pointer.
If pointer is NULL, an empty String is returned.
Safety
The purpose of this method is to allow creating a String from a pointer
returned by C code. Do not use this method unless you have somehow verified
that the pointer is a valid NULL terminated C string.
If the pointer points to invalid memory or isn't NULL terminated, the behavior is undefined and likely results in a crash.
Examples
String.from_pointer("hello".pointer) == "hello" # => true
join
Show source codeHide source code
fn pub static join[T: ToString, I: Iter[T]](
iter: move I,
with: String,
) -> String {
let buf = StringBuffer.new
for (idx, val) in iter.with_index {
if idx > 0 { buf.push(with) }
buf.push(val.to_string)
}
buf.into_string
}fn pub static join[T: ToString, I: Iter[T]](iter: move I, with: String) -> StringReturn a String that contains the values of the iterator, separated by the
value of the with argument.
Examples
let vals = [10, 20, 30].into_iter
String.join(vals, with: ',') => '10,20,30'
try_from_bytes
Show source codeHide source code
fn pub static try_from_bytes[B: Bytes](bytes: ref B) -> Option[String] {
let len = bytes.size
if len == 0 { return Option.Some('') }
let prim = inko_string_try_from_bytes(bytes.pointer, len)
if prim.size > -1 {
Option.Some(from_borrowed_primitive(prim))
} else {
Option.None
}
}fn pub static try_from_bytes[B: Bytes](bytes: ref B) -> Option[String]Returns a new String created from the given Bytes.
If the bytes contain invalid UTF-8 sequences, an Option.None is returned.
Examples
String.try_from_bytes('abc'.to_byte_array) # => Option.Some('abc')
String.try_from_bytes(ByteArray.from_array([255])) # => Option.None
Instance methods
!=
Show source codeHide source code
fn pub !=(other: ref Self) -> Bool {
!(self == other)
}fn pub !=(other: ref Self) -> BoolReturns true if self and the given object are not equal to each other.
+
Show source codeHide source code
fn pub inline +(other: String) -> String {
let tot = size + other.size
let new = alloc.allocate(tot + 1)
alloc.copy(from: pointer, to: new, size: size)
alloc.copy(from: other.pointer, to: ptr.add(new, size), size: other.size)
alloc.write(byte: 0, to: ptr.add(new, tot), size: 1)
String(size: tot, ptr: new)
}fn pub inline +(other: String) -> StringConcatenates self and the given String, returning a new String.
Examples
'hello ' + 'world' # => 'hello world'
<
Show source codeHide source code
fn pub <(other: ref Self) -> Bool {
match cmp(other) {
case Less -> true
case _ -> false
}
}fn pub <(other: ref Self) -> BoolReturns true if self is lower than the given argument.
<=
Show source codeHide source code
fn pub <=(other: ref Self) -> Bool {
match cmp(other) {
case Less or Equal -> true
case _ -> false
}
}fn pub <=(other: ref Self) -> BoolReturns true if self is lower than or equal to the given argument.
==
Show source codeHide source code
fn pub ==(other: String) -> Bool {
let lsize = self.size
if lsize == other.size { ptr.equal(@ptr, other.ptr, lsize) } else { false }
}fn pub ==(other: String) -> BoolReturns true if the current String and other are equal to each other.
Examples
Returns true if two Strings are equal:
'foo' == 'foo' # => true
Returns false if two Strings are not equal:
'foo' == 'bar' # => false
>
Show source codeHide source code
fn pub >(other: ref Self) -> Bool {
match cmp(other) {
case Greater -> true
case _ -> false
}
}fn pub >(other: ref Self) -> BoolReturns true if self is greater than the given argument.
>=
Show source codeHide source code
fn pub >=(other: ref Self) -> Bool {
match cmp(other) {
case Greater or Equal -> true
case _ -> false
}
}fn pub >=(other: ref Self) -> BoolReturns true if self is equal to or greater than the given argument.
bytes
Show source codeHide source code
fn pub bytes -> Iter[ref Self] {
Iter(source: self, index: 0)
}fn pub bytes -> Iter[ref Self]Returns an iterator over the bytes in self.
Examples
let bytes = ByteArray.from_array([10, 20, 30])
let iter = bytes.bytes
iter.next # => Option.Some(10)
chars
Show source codeHide source code
fn pub inline chars -> Chars {
Chars(string: self, iter: inko_string_chars(to_primitive))
}fn pub inline chars -> CharsReturns an iterator over the characters (= extended grapheme clusters) in
self.
Examples
'๐๐'.chars.to_array # => ['๐', '๐']
clone
Show source codeHide source code
fn pub inline clone -> String {
self
}fn pub inline clone -> StringCreates a clone of self.
The returned value is an owned value that is the same type as the receiver
of this method. For example, cloning a ref Array[Int] results in a
Array[Int], not another ref Array[Int].
cmp
Show source codeHide source code
fn pub cmp(other: String) -> Ordering {
let mut max = min(size, other.size)
let mut idx = 0
while idx < max {
match byte_unchecked(idx).cmp(other.byte_unchecked(idx)) {
case Equal -> idx += 1
case ord -> return ord
}
}
size.cmp(other.size)
}fn pub cmp(other: String) -> OrderingPerforms a byte-wise comparison of self with other.
This method does not perform lexicographic sorting, and thus produces unreliable results for multi-byte strings.
Examples
'aaa'.cmp('bbb') # => Ordering.Less 'aab'.cmp('aaa') # => Ordering.Greater
contains?
Show source codeHide source code
fn pub contains?(value: String) -> Bool {
contains_bytes?(value)
}fn pub contains?(value: String) -> BoolReturns true if self contains the given String.
If you instead want to use a ByteArray or Slice as the argument, use
String.contains_bytes? instead.
Examples
'hello world'.contains?('hello') # => true
contains_bytes?
Show source codeHide source code
fn pub contains_bytes?[B: Bytes](bytes: ref B) -> Bool {
index_of(bytes, starting_at: 0).some?
}fn pub contains_bytes?[B: Bytes](bytes: ref B) -> BoolReturns true if self contains the given byte sequence.
Examples
'hello'.contains_bytes?('hello') # => true
empty?
Show source codeHide source code
fn pub empty? -> Bool {
size == 0
}fn pub empty? -> BoolReturns true if self is empty.
Examples
''.empty? # => true
'hello'.empty? # => false
ends_with?
Show source codeHide source code
fn pub ends_with?[T: Bytes](suffix: ref T) -> Bool {
ptr.ends_with?(pointer, size, suffix.pointer, suffix.size)
}fn pub ends_with?[T: Bytes](suffix: ref T) -> BoolReturns true if self ends with the given sequence of bytes.
Examples
'hello'.ends_with?('o'.to_byte_array) # => true
'hello'.ends_with?('o') # => true
equals?
Show source codeHide source code
fn pub equals?[O: Bytes](other: ref O) -> Bool {
let len = size
len == other.size and (len == 0 or ptr.equal(pointer, other.pointer, len))
}fn pub equals?[O: Bytes](other: ref O) -> BoolReturns true if self and other contain identical bytes.
This allows comparing of any Bytes type with any other Bytes type (e.g.
comparing a String to a ByteArray). In contrast, methods such as
String.== only support comparing against values of the same type.
Examples
'hello'.equals?('hello') # => true
'hello'.equals?('hello'.to_byte_array) # => true
equals_while_ignoring_case?
Show source codeHide source code
fn pub equals_while_ignoring_case?[O: Bytes](other: ref O) -> Bool {
let len = size
if len == 0 { return true }
if len != other.size { return false }
let lhs = pointer
let rhs = other.pointer
let mut idx = 0
# Since we have to convert ASCII bytes to lowercase (when necessary) we
# can't use a more efficient comparison and instead have to compare the data
# byte by byte.
while idx < len {
let mut a = ptr.add(lhs, idx).0 as Int
let mut b = ptr.add(rhs, idx).0 as Int
if upper?(a) { a = to_lower(a) }
if upper?(b) { b = to_lower(b) }
if a != b { return false }
idx += 1
}
true
}fn pub equals_while_ignoring_case?[O: Bytes](other: ref O) -> BoolReturns true if self and other contain identical bytes, using an ASCII
case-insensitive comparison.
This method only performs case-insensitive matching for characters in the ASCII range, meaning that "foo" and "FOO" are considered identical but "รก" and "ร" are considered different.
Examples
'foo'.equals_while_ignoring_case?('foo') # => true
'foo'.equals_while_ignoring_case?('FOO') # => true
'abc'.equals_while_ignoring_case?('def') # => false
'รก'.equals_while_ignoring_case?('ร') # => false
escaped
Show source codeHide source code
fn pub escaped -> String {
# If the String doesn't contain any special characters then we can/should
# avoid the allocations that take place below.
if !escape? { return self }
let buff = ByteArray.new
let mut i = 0
while i < size {
let byte = byte_unchecked(i := i + 1)
match ESCAPE_TABLE.get(byte) {
case Ok(-1) or Error(_) -> buff.push(byte)
case Ok(byte) -> {
buff.push(BSLASH)
buff.push(byte)
}
}
}
buff.into_string
}fn pub escaped -> StringReturns a copy of self with all special characters escaped.
The following characters are escaped:
- Double quotes
- Tabs
- Newlines
- Carriage returns
- Backspace
- Form feed
- Backslash
Examples
"hello\nworld" # => 'hello\nworld'
"hello\\world" # => 'hello\\world'
fmt
Show source codeHide source code
fn pub fmt(formatter: mut Formatter) {
formatter.write('"')
formatter.write(escaped)
formatter.write('"')
}fn pub fmt(formatter: mut Formatter)Formats self in a human-readable format for debugging purposes.
get
Show source codeHide source code
fn pub inline get(index: Int) -> Result[Int, OutOfBounds] {
try check_bounds(index, size)
Result.Ok(byte_unchecked(index))
}fn pub inline get(index: Int) -> Result[Int, OutOfBounds]Returns the byte at the given index.
If the index is out of bounds, a std.bounds.OutOfBounds error is returned.
Examples
'abc'.get(0) # => Result.Ok(97)
'abc'.get(10) # => Result.Error(OutOfBounds(...))
hash
Show source codeHide source code
fn pub hash[H: mut + Hasher](hasher: mut H) {
hash_bytes(self, hasher)
}fn pub hash[H: mut + Hasher](hasher: mut H: mut)Writes the hash for self into the given Hasher.
index_of
Show source codeHide source code
fn pub index_of[B: Bytes](value: ref B, starting_at: Int) -> Option[Int] {
# This is a naive string searching algorithm (see
# https://en.wikipedia.org/wiki/String-searching_algorithm) for more details
# on the various algorithms.
#
# We're using the naive algorithm because:
#
# 1. It's easy to implement
# 2. It doesn't require any pre-processing
# 3. At the time of writing there was no need for something more performant
let find_size = value.size
if find_size == 0 or size == 0 or find_size > size { return Option.None }
let mut a = starting_at
let max = size - find_size
while a <= max {
let mut b = 0
while b < find_size and get(a + b) == value.get(b) { b += 1 }
if b == find_size { return Option.Some(a) }
a += 1
}
Option.None
}fn pub index_of[B: Bytes](value: ref B, starting_at: Int) -> Option[Int]Returns the byte index of the first occurrence of the given sequence of bytes, starting at the given byte index.
Examples
'hello'.index_of('h', starting_at: 0) # => Option.Some(0)
'hello'.index_of('l', starting_at: 0) # => Option.Some(2)
'hello'.index_of('l', starting_at: 3) # => Option.Some(3)
'hello'.index_of('x', starting_at: 0) # => Option.None
into_byte_array
Show source codeHide source code
fn pub inline move into_byte_array -> ByteArray {
to_byte_array
}fn pub inline move into_byte_array -> ByteArrayinto_string
Show source codeHide source code
fn pub inline move into_string -> String {
self
}fn pub inline move into_string -> StringMoves self into a String.
pad_end
Show source codeHide source code
fn pub pad_end(with: String, chars: Int) -> String {
self + padding(with, chars: self.chars.count, pad_to: chars)
}fn pub pad_end(with: String, chars: Int) -> StringReturns a new String that is padded with another String until the given
number of characters is reached.
The padding is applied at the end of the new String.
Examples
'hello'.pad_end(with: ' ', chars: 7) # => 'hello '
'hello'.pad_end(with: ' ', chars: 5) # => 'hello'
pad_start
Show source codeHide source code
fn pub pad_start(with: String, chars: Int) -> String {
padding(with, chars: self.chars.count, pad_to: chars) + self
}fn pub pad_start(with: String, chars: Int) -> StringReturns a new String that is padded with another String until the given
number of characters is reached.
The padding is applied at the start of the new String.
Examples
'hello'.pad_start(with: ' ', chars: 7) # => ' hello'
'hello'.pad_start(with: ' ', chars: 5) # => 'hello'
pointer
Show source codeHide source code
fn pub inline pointer -> Pointer[UInt8] {
@ptr
}fn pub inline pointer -> Pointer[UInt8]Returns a raw pointer to the bytes of self.
This method is meant to be used when passing strings to foreign functions
(i.e. *char arguments). You should avoid using it for anything else.
repeat
Show source codeHide source code
fn pub repeat(times: Int) -> String {
match times {
case 0 -> ''
case 1 -> self
case _ -> {
let buf = StringBuffer.new
times.times(fn (_) { buf.push(clone) })
buf.into_string
}
}
}fn pub repeat(times: Int) -> StringReturns a new String that contains self multiple times.
Examples
'a'.repeat(4) # => 'aaaa'
replace
Show source codeHide source code
fn pub replace(string: String, with: String) -> String {
# Different languages handle the pattern being empty differently. For
# example, Javascript and Node only match the start of the string if the
# pattern is empty. Other languages such as Ruby and Python appear to inject
# the replacement in between every character, such that
# `'AB'.replace('', ',')` results in `,A,B,`.
#
# We make the decision to just _not_ do any replacements in this case, as
# replacing an empty string is nonsensical to begin with.
if string.size == 0 { return self }
let buf = ByteArray.new
let mut start = 0
let mut last = 0
loop {
match index_of(string, start) {
case Some(i) -> {
if i > last { buf.append(slice(start: last, end: i)) }
buf.append(with.slice(start: 0, end: with.size))
start = i + string.size
last = start
}
case _ -> {
if start < size { buf.append(slice(start: start, end: size)) }
break
}
}
}
buf.into_string
}fn pub replace(string: String, with: String) -> StringReplaces all occurrences of string with the value in with, returning the
result as a new String.
If the string argument is an empty String, this method doesn't perform
any replacements and instead returns a copy of self.
Examples
'foo foo'.replace('foo', with: 'bar') # => 'bar bar'
scalars
Show source codeHide source code
fn pub inline scalars -> Scalars[Self] {
Scalars.new(self)
}fn pub inline scalars -> Scalars[String]Returns an iterator over the UTF-8 scalars in self.
Examples
'foo'.scalars.to_array # => [102, 111, 111]
'๐คฆ๐ผโโ๏ธ'.scalars.to_array # => [129318, 127996, 8205, 9794, 65039]
size
Show source codeHide source code
fn pub inline size -> Int {
@size
}fn pub inline size -> IntReturns the size of the String in bytes.
Examples
Getting the byte size of a String:
'foo'.size # => 3
'๐'.size # => 4
slice
Show source codeHide source code
fn pub slice(start: Int, end: Int) -> Slice[Self] {
Slice.checked(self, start, end)
}fn pub slice(start: Int, end: Int) -> Slice[String]Slices self into a slice of bytes using a byte range from start until
(but excluding) end.
Both the start and end arguments are byte indexes.
The start index is allowed to be equal to the size of self, but only if
end is the same as start. Thus given a String with a size of 4,
string.slice(4, 4) is valid.
Panics
This method panics if start or end is out of bounds.
Examples
'๐'.slice(start: 0, end: 4).to_string # => '๐'
'๐'.slice(start: 0, end: 3).to_string # => "\u{FFFD}"
split
Show source codeHide source code
fn pub split(separator: String) -> Stream[Slice[String]] {
Slice.new(self, 0, size).split(separator)
}fn pub split(separator: String) -> Stream[Slice[String]]Splits self into an iterator of slices of the data in self, each
separated by the given separator.
Examples
Splitting a String using a single character as the separator:
let iter = 'foo/bar/baz'.split('/')
iter.next.get.to_string # => 'foo'
iter.next.get.to_string # => 'bar'
Splitting a String using multiple characters as the separator:
let iter = 'foo::bar::baz'.split('::')
iter.next.get.to_string # => 'foo'
iter.next.get.to_string # => 'bar'
split_once
Show source codeHide source code
fn pub split_once(
separator: String,
) -> Option[(Slice[String], Slice[String])] {
Slice.new(self, 0, size).split_once(separator)
}fn pub split_once(separator: String) -> Option[(Slice[String], Slice[String])]Splits self on the first occurrence of separator.
Refer to the documentation of Slice.split_once for more details.
Examples
let left_right = 'key=value'.split_once('=').get
left_right.0.to_string # => 'key'
left_right.1.to_string # => 'value'
starts_with?
Show source codeHide source code
fn pub starts_with?[T: Bytes](prefix: ref T) -> Bool {
ptr.starts_with?(pointer, size, prefix.pointer, prefix.size)
}fn pub starts_with?[T: Bytes](prefix: ref T) -> BoolReturns true if self starts with the given sequence of bytes.
Examples
'hello'.starts_with?('h'.to_byte_array) # => true
'hello'.starts_with?('h') # => true
strip_prefix
Show source codeHide source code
fn pub strip_prefix(prefix: String) -> Option[String] {
if !starts_with?(prefix) { return Option.None }
if size == prefix.size {
Option.Some('')
} else {
Option.Some(slice(start: prefix.size, end: size).to_string)
}
}fn pub strip_prefix(prefix: String) -> Option[String]Returns a new String without the given prefix.
If self starts with the prefix, a Option.Some is returned containing the
substring after the prefix. If self doesn't start with the prefix, an
Option.None is returned.
Examples
'xhellox'.strip_prefix('x') # => Option.Some('hellox')
'xhellox'.strip_prefix('y') # => Option.None
strip_suffix
Show source codeHide source code
fn pub strip_suffix(suffix: String) -> Option[String] {
if !ends_with?(suffix) { return Option.None }
Option.Some(slice(start: 0, end: size - suffix.size).to_string)
}fn pub strip_suffix(suffix: String) -> Option[String]Returns a new String without the given suffix.
If self ends with the suffix, a Option.Some is returned containing the
substring before the prefix. If self doesn't end with the suffix, an
Option.None is returned.
Examples
'xhellox'.strip_suffix('x') # => Option.Some('xhello')
'xhellox'.strip_suffix('y') # => Option.None
substring
Show source codeHide source code
fn pub substring(start: Int, end: Int) -> String {
let buff = StringBuffer.new
for (index, char) in self.chars.with_index {
if index >= end { break } else if index >= start { buff.push(char) }
}
buff.into_string
}fn pub substring(start: Int, end: Int) -> StringSlices self into a substring using a character range from start until
(but excluding) end.
Both the start and end arguments are character indexes, not byte
indexes. If start is less than zero, it's treated as if it were set to
zero. If end is zero or start is greater than or equal to end, the
returned value is always an empty String.
Slicing a String into a substring is not a constant-time operation,
instead it's O(n) where n is the number of characters in the String.
Examples
'hello_world'.substring(start: 0, end: 5) # => 'hello'
'hello_world'.substring(start: 0, end: 50) # => 'hello'
'๐'.substring(start: 0, end: 1) # => '๐'
to_byte_array
Show source codeHide source code
fn pub inline to_byte_array -> ByteArray {
let bytes = ByteArray.new
let _ = bytes.append(self)
bytes
}fn pub inline to_byte_array -> ByteArrayto_lower
Show source codeHide source code
fn pub inline to_lower -> String {
String.from_primitive(inko_string_to_lower(to_primitive))
}fn pub inline to_lower -> StringReturns the lowercase equivalent of the current String.
Examples
Converting a String containing only ASCII symbols:
'HELLO'.to_lower # => 'hello'
Converting a String containing Unicode symbols:
'ร'.to_lower # => 'รค'
Converting a String containing both ASCII and Unicode symbols:
'Aร'.to_lower # => 'aรค'
to_path
Show source codeHide source code
fn pub inline to_path -> Path {
Path.new(self)
}fn pub inline to_path -> PathConverts self to a Path
Examples
'/tmp/test.txt'.to_path # => Path.new('/tmp/test.txt')
to_slice
Show source codeHide source code
fn pub to_slice -> Slice[Self] {
Slice.new(self, 0, size)
}fn pub to_slice -> Slice[String]Returns a Slice that covers all of self.
to_string
Show source codeHide source code
fn pub inline to_string -> String {
clone
}fn pub inline to_string -> StringConverts self to a String.
to_upper
Show source codeHide source code
fn pub inline to_upper -> String {
String.from_primitive(inko_string_to_upper(to_primitive))
}fn pub inline to_upper -> StringReturns the uppercase equivalent of the current String.
Examples
Converting a String containing only ASCII symbols:
'hello'.to_upper # => 'HELLO'
Converting a String containing Unicode symbols:
'รค'.to_upper # => 'ร'
Converting a String containing both ASCII and Unicode symbols:
'aรค'.to_upper # => 'Aร'
trim
Show source codeHide source code
fn pub trim -> String {
Slice.new(self, 0, size).trim.to_string
}fn pub trim -> StringReturns a new String with both leading and trailing whitespace removed.
Examples
' hello '.trim # => 'hello'
" hello\t".trim # => 'hello'
trim_end
Show source codeHide source code
fn pub trim_end -> String {
Slice.new(self, 0, size).trim_end.to_string
}fn pub trim_end -> StringReturns a new String without any trailing whitespace.
Examples
'hello '.trim_end # => 'hello'
"hello\t".trim_end # => 'hello'
trim_start
Show source codeHide source code
fn pub trim_start -> String {
Slice.new(self, 0, size).trim_start.to_string
}fn pub trim_start -> StringReturns a new String without any leading whitespace.
Examples
' hello'.trim_start # => 'hello'
"\thello".trim_start # => 'hello'
Implemented traits
Bytes
impl Bytes for StringIntoByteArray
impl IntoByteArray for StringToByteArray
impl ToByteArray for StringToSlice
impl ToSlice[String] for StringClone
impl Clone for StringCompare
impl Compare for StringEqual
impl Equal for StringDrop
impl Drop for StringFormat
impl Format for StringHash
impl Hash for StringAdd
impl Add[String, String] for StringIntoString
impl IntoString for StringToString
impl ToString for String