☰

# std/strutils

Theme:

- Manual
- Standard library
- Index
- Compiler docs
- Fusion docs
- devel, stable

Search:
Source Edit

The system module defines several common functions for working with strings, such as:

- `$` for converting other data-types to strings
- `&` for string concatenation
- `add` for adding a new character or a string to the existing one
- `in` (alias for `contains`) and `notin` for checking if a character is in a string

This module builds upon that, providing additional functionality in form of procedures, iterators and templates for strings.

Example:

    import std/strutils
    let
      numbers = @[867, 5309]
      multiLineString = "first line\nsecond line\nthird line"

    let jenny = numbers.join("-")
    assert jenny == "867-5309"

    assert splitLines(multiLineString) ==
           @["first line", "second line", "third line"]
    assert split(multiLineString) == @["first", "line", "second",
                                       "line", "third", "line"]
    assert indent(multiLineString, 4) ==
           "    first line\n    second line\n    third line"
    assert 'z'.repeat(5) == "zzzzz"

The chaining of functions is possible thanks to the method call syntax:

Example:

    import std/strutils
    from std/sequtils import map

    let jenny = "867-5309"
    assert jenny.split('-').map(parseInt) == @[867, 5309]

    assert "Beetlejuice".indent(1).repeat(3).strip ==
           "Beetlejuice Beetlejuice Beetlejuice"

This module is available for the JavaScript target.

See also:

- strformat module for string interpolation and formatting
- unicode module for Unicode UTF-8 handling
- sequtils module for operations on container types (including strings)
- parsecsv module for a high-performance CSV parser
- parseutils module for lower-level parsing of tokens, numbers, identifiers, etc.
- parseopt module for command-line parsing
- pegs module for PEG (Parsing Expression Grammar) support
- strtabs module for efficient hash tables (dictionaries, in some programming languages) mapping from strings to strings
- ropes module for rope data type, which can represent very long strings efficiently
- re module for regular expression (regex) support
- strscans for `scanf` and `scanp` macros, which offer easier substring extraction than regular expressions

# Imports

parseutils, math, algorithm, enumutils, bitops, unicode, since, jsutils, strimpl, assertions

# Types

    BinaryPrefixMode = enum
      bpIEC, bpColloquial

  The different names for binary prefixes. Source Edit

    FloatFormatMode = enum
      ffDefault,                ## use the shorter floating point notation
      ffDecimal,                ## use decimal floating point notation
      ffScientific               ## use scientific notation (using `e` character)

  The different modes of floating point formatting. Source Edit

    SkipTable = array[char, int]

  Character table for efficient substring search. Source Edit

# Consts

    AllChars = {'\x00'..'\xFF'}

  A set with all the possible characters.

  Not very useful by its own, you can use it to create inverted sets to make the find func find invalid characters in strings. Example:

      let invalid = AllChars - Digits
      doAssert "01234".find(invalid) == -1
      doAssert "01A34".find(invalid) == 2

  Source Edit

    Digits = {'0'..'9'}

  The set of digits. Source Edit

    HexDigits = {'0'..'9', 'A'..'F', 'a'..'f'}

  The set of hexadecimal digits. Source Edit

    IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}

  The set of characters an identifier can consist of. Source Edit

    IdentStartChars = {'a'..'z', 'A'..'Z', '_'}

  The set of characters an identifier can start with. Source Edit

    Letters = {'A'..'Z', 'a'..'z'}

  The set of letters. Source Edit

    LowercaseLetters = {'a'..'z'}

  The set of lowercase ASCII letters. Source Edit

    Newlines = {'\r', '\n'}

  The set of characters a newline terminator can start with (carriage return, line feed). Source Edit

    PrintableChars = {'\t'..'\r', ' '..'~'}

  The set of all printable ASCII characters (letters, digits, whitespace, and punctuation characters). Source Edit

    PunctuationChars = {'!'..'/', ':'..'@', '['..'`', '{'..'~'}

  The set of all ASCII punctuation characters. Source Edit

    UppercaseLetters = {'A'..'Z'}

  The set of uppercase ASCII letters. Source Edit

    Whitespace = {' ', '\t', '\v', '\r', '\n', '\f'}

  All the characters that count as whitespace (space, tab, vertical tab, carriage return, new line, form feed). Source Edit

# Procs

    func `%`(formatstr, a: string): string {....gcsafe, extern: "nsuFormatSingleElem",
        raises: [ValueError], tags: [], forbids: [].}

  This is the same as `formatstr % [a]` (see % func). Source Edit

    func `%`(formatstr: string; a: openArray[string]): string {....gcsafe,
        extern: "nsuFormatOpenArray", raises: [ValueError], tags: [], forbids: [].}

  Interpolates a format string with the values from `a`.

  The substitution operator performs string substitutions in `formatstr` and returns a modified `formatstr`. This is often called string interpolation.

  This is best explained by an example:

      "$1 eats $2." % ["The cat", "fish"]

  Results in:

      "The cat eats fish."

  The substitution variables (the thing after the `$`) are enumerated from 1 to `a.len`. To produce a verbatim `$`, use `$$`. The notation `$#` can be used to refer to the next substitution variable:

      "$# eats $#." % ["The cat", "fish"]

  Substitution variables can also be words (that is `[A-Za-z_]+[A-Za-z0-9_]*`) in which case the arguments in `a` with even indices are keys and with odd indices are the corresponding values. An example:

      "$animal eats $food." % ["animal", "The cat", "food", "fish"]

  Results in:

      "The cat eats fish."

  The variables are compared with `cmpIgnoreStyle`. `ValueError` is raised if an ill-formed format string has been passed to the `%` operator.

  See also:

  - strformat module for string interpolation and formatting
  Source Edit

    func abbrev(s: string; possibilities: openArray[string]): int {....raises: [],
        tags: [], forbids: [].}

  Returns the index of the first item in `possibilities` which starts with `s`, if not ambiguous.

  Returns -1 if no item has been found and -2 if multiple items match.

  Example:

      doAssert abbrev("fac", ["college", "faculty", "industry"]) == 1
      doAssert abbrev("foo", ["college", "faculty", "industry"]) == -1 # Not found
      doAssert abbrev("fac", ["college", "faculty", "faculties"]) == -2 # Ambiguous
      doAssert abbrev("college", ["college", "colleges", "industry"]) == 0

  Source Edit

    func addf(s: var string; formatstr: string; a: varargs[string, `$`]) {....gcsafe,
        extern: "nsuAddf", raises: [ValueError], tags: [], forbids: [].}

  The same as `add(s, formatstr % a)`, but more efficient. Source Edit

    func addSep(dest: var string; sep = ", "; startLen: Natural = 0) {.inline,
        ...raises: [], tags: [], forbids: [].}

  Adds a separator to `dest` only if its length is bigger than `startLen`.

  A shorthand for:

      if dest.len > startLen: add(dest, sep)

  This is often useful for generating some code where the items need to be separated by `sep`. `sep` is only added if `dest` is longer than `startLen`. The following example creates a string describing an array of integers.

  Example:

      var arr = "["
      for x in items([2, 3, 5, 7, 11]):
        addSep(arr, startLen = len("["))
        add(arr, $x)
      add(arr, "]")
      doAssert arr == "[2, 3, 5, 7, 11]"

  Source Edit

    func align(s: string; count: Natural; padding = ' '): string {....gcsafe,
        extern: "nsuAlignString", raises: [], tags: [], forbids: [].}

  Aligns a string `s` with `padding`, so that it is of length `count`.

  `padding` characters (by default spaces) are added before `s` resulting in right alignment. If `s.len >= count`, no spaces are added and `s` is returned unchanged. If you need to left align a string use the alignLeft func.

  See also:

  - alignLeft func
  - spaces func
  - indent func
  - center func

  Example:

      assert align("abc", 4) == " abc"
      assert align("a", 0) == "a"
      assert align("1232", 6) == "  1232"
      assert align("1232", 6, '#') == "##1232"

  Source Edit

    func alignLeft(s: string; count: Natural; padding = ' '): string {....raises: [],
        tags: [], forbids: [].}

  Left-Aligns a string `s` with `padding`, so that it is of length `count`.

  `padding` characters (by default spaces) are added after `s` resulting in left alignment. If `s.len >= count`, no spaces are added and `s` is returned unchanged. If you need to right align a string use the align func.

  See also:

  - align func
  - spaces func
  - indent func
  - center func

  Example:

      assert alignLeft("abc", 4) == "abc "
      assert alignLeft("a", 0) == "a"
      assert alignLeft("1232", 6) == "1232  "
      assert alignLeft("1232", 6, '#') == "1232##"

  Source Edit

    func allCharsInSet(s: string; theSet: set[char]): bool {....raises: [], tags: [],
        forbids: [].}

  Returns true if every character of `s` is in the set `theSet`.

  Example:

      doAssert allCharsInSet("aeea", {'a', 'e'}) == true
      doAssert allCharsInSet("", {'a', 'e'}) == true

  Source Edit

    func capitalizeAscii(s: string): string {....gcsafe, extern: "nsuCapitalizeAscii",
        raises: [], tags: [], forbids: [].}

  Converts the first character of string `s` into upper case.

  This works only for the letters `A-Z`. Use Unicode module for UTF-8 support.

  See also:

  - toUpperAscii func

  Example:

      doAssert capitalizeAscii("foo") == "Foo"
      doAssert capitalizeAscii("-bar") == "-bar"

  Source Edit

    func center(s: string; width: int; fillChar: char = ' '): string {....gcsafe,
        extern: "nsuCenterString", raises: [], tags: [], forbids: [].}

  Return the contents of `s` centered in a string `width` long using `fillChar` (default: space) as padding.

  The original string is returned if `width` is less than or equal to `s.len`.

  See also:

  - align func
  - alignLeft func
  - spaces func
  - indent func

  Example:

      let a = "foo"
      doAssert a.center(2) == "foo"
      doAssert a.center(5) == " foo "
      doAssert a.center(6) == " foo  "

  Source Edit

    func cmpIgnoreCase(a, b: string): int {....gcsafe, extern: "nsuCmpIgnoreCase",
                                            raises: [], tags: [], forbids: [].}

  Compares two strings in a case insensitive manner. Returns:

  `0` if a == b
  `< 0` if a < b
  `> 0` if a > b

  Example:

      doAssert cmpIgnoreCase("FooBar", "foobar") == 0
      doAssert cmpIgnoreCase("bar", "Foo") < 0
      doAssert cmpIgnoreCase("Foo5", "foo4") > 0

  Source Edit

    func cmpIgnoreStyle(a, b: string): int {....gcsafe, extern: "nsuCmpIgnoreStyle",
        raises: [], tags: [], forbids: [].}

  Semantically the same as `cmp(normalize(a), normalize(b))`. It is just optimized to not allocate temporary strings. This should NOT be used to compare Nim identifier names. Use macros.eqIdent for that.

  Returns:

  `0` if a == b
  `< 0` if a < b
  `> 0` if a > b

  Example:

      doAssert cmpIgnoreStyle("foo_bar", "FooBar") == 0
      doAssert cmpIgnoreStyle("foo_bar_5", "FooBar4") > 0

  Source Edit

    func contains(s, sub: string): bool {....raises: [], tags: [], forbids: [].}

  Same as `find(s, sub) >= 0`.

  See also:

  - find func
  Source Edit

    func contains(s: string; chars: set[char]): bool {....raises: [], tags: [],
        forbids: [].}

  Same as `find(s, chars) >= 0`.

  See also:

  - find func
  Source Edit

    func continuesWith(s, substr: string; start: Natural): bool {....gcsafe,
        extern: "nsuContinuesWith", raises: [], tags: [], forbids: [].}

  Returns true if `s` continues with `substr` at position `start`.

  If `substr == ""` true is returned.

  See also:

  - startsWith func
  - endsWith func

  Example:

      let a = "abracadabra"
      doAssert a.continuesWith("ca", 4) == true
      doAssert a.continuesWith("ca", 5) == false
      doAssert a.continuesWith("dab", 6) == true

  Source Edit

    func count(s: string; sub: char): int {....gcsafe, extern: "nsuCountChar",
                                            raises: [], tags: [], forbids: [].}

  Counts the occurrences of the character `sub` in the string `s`.

  See also:

  - countLines func
  Source Edit

    func count(s: string; sub: string; overlapping: bool = false): int {....gcsafe,
        extern: "nsuCountString", raises: [], tags: [], forbids: [].}

  Counts the occurrences of a substring `sub` in the string `s`. Overlapping occurrences of `sub` only count when `overlapping` is set to true (default: false).

  See also:

  - countLines func
  Source Edit

    func count(s: string; subs: set[char]): int {....gcsafe, extern: "nsuCountCharSet",
        raises: [], tags: [], forbids: [].}

  Counts the occurrences of the group of character `subs` in the string `s`.

  See also:

  - countLines func
  Source Edit

    func countLines(s: string): int {....gcsafe, extern: "nsuCountLines", raises: [],
                                      tags: [], forbids: [].}

  Returns the number of lines in the string `s`.

  This is the same as `len(splitLines(s))`, but much more efficient because it doesn't modify the string creating temporary objects. Every character literal newline combination (CR, LF, CR-LF) is supported.

  In this context, a line is any string separated by a newline combination. A line can be an empty string.

  See also:

  - splitLines func

  Example:

      doAssert countLines("First line\l and second line.") == 2

  Source Edit

    func dedent(s: string; count: Natural = indentation(s)): string {....gcsafe,
        extern: "nsuDedent", raises: [], tags: [], forbids: [].}

  Unindents each line in `s` by `count` amount of `padding`. The only difference between this and the unindent func is that this by default only cuts off the amount of indentation that all lines of `s` share as opposed to all indentation. It only supports spaces as padding.

  Note: This does not preserve the new line characters used in `s`.

  See also:

  - unindent func
  - align func
  - alignLeft func
  - spaces func
  - indent func

  Example:

      let x = """
            Hello
              There
          """.dedent()

      doAssert x == "Hello\n  There\n"

  Source Edit

    func delete(s: var string; first, last: int) {....gcsafe, extern: "nsuDelete",
        deprecated: "use `delete(s, first..last)`", raises: [], tags: [],
        forbids: [].}

  Deprecated: use `delete(s, first..last)`
  Deletes in `s` the characters at positions `first .. last` (both ends included).

  Example: cmd: --warning:deprecated:off

      var a = "abracadabra"

      a.delete(4, 5)
      doAssert a == "abradabra"

      a.delete(1, 6)
      doAssert a == "ara"

      a.delete(2, 999)
      doAssert a == "ar"

  Source Edit

    func delete(s: var string; slice: Slice[int]) {....raises: [], tags: [],
        forbids: [].}

  Deletes the items `s[slice]`, raising `IndexDefect` if the slice contains elements out of range.

  This operation moves all elements after `s[slice]` in linear time, and is the string analog to `sequtils.delete`.

  Example:

      var a = "abcde"
      doAssertRaises(IndexDefect): a.delete(4..5)
      assert a == "abcde"
      a.delete(4..4)
      assert a == "abcd"
      a.delete(1..2)
      assert a == "ad"
      a.delete(1..<1) # empty slice
      assert a == "ad"

  Source Edit

    func endsWith(s, suffix: string): bool {....gcsafe, extern: "nsuEndsWith",
        raises: [], tags: [], forbids: [].}

  Returns true if `s` ends with `suffix`.

  If `suffix == ""` true is returned.

  See also:

  - startsWith func
  - continuesWith func
  - removeSuffix func

  Example:

      let a = "abracadabra"
      doAssert a.endsWith("abra") == true
      doAssert a.endsWith("dab") == false

  Source Edit

    func endsWith(s: string; suffix: char): bool {.inline, ...raises: [], tags: [],
        forbids: [].}

  Returns true if `s` ends with `suffix`.

  See also:

  - startsWith func
  - continuesWith func
  - removeSuffix func

  Example:

      let a = "abracadabra"
      doAssert a.endsWith('a') == true
      doAssert a.endsWith('b') == false

  Source Edit

    func escape(s: string; prefix = "\""; suffix = "\""): string {....gcsafe,
        extern: "nsuEscape", raises: [], tags: [], forbids: [].}

  Escapes a string `s`.
  Note: The escaping scheme is different from `system.addEscapedChar`.
  - replaces `'\0'..'\31'` and `'\127'..'\255'` by `\xHH` where `HH` is its hexadecimal value
  - replaces `\` by `\\`
  - replaces `'` by `\'`
  - replaces `"` by `\"`

  The resulting string is prefixed with `prefix` and suffixed with `suffix`. Both may be empty strings.

  See also:

  - addEscapedChar proc
  - unescape func for the opposite operation
  Source Edit

    func find(a: SkipTable; s, sub: string; start: Natural = 0; last = -1): int {.
        ...gcsafe, extern: "nsuFindStrA", raises: [], tags: [], forbids: [].}

  Searches for `sub` in `s` inside range `start..last` using preprocessed table `a`. If `last` is unspecified, it defaults to `s.high` (the last element).

  Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.

  See also:

  - initSkipTable func
  - initSkipTable func
  Source Edit

    func find(s, sub: string; start: Natural = 0; last = -1): int {....gcsafe,
        extern: "nsuFindStr", raises: [], tags: [], forbids: [].}

  Searches for `sub` in `s` inside range `start..last` (both ends included). If `last` is unspecified or negative, it defaults to `s.high` (the last element).

  Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. Otherwise the index returned is relative to `s[0]`, not `start`. Subtract `start` from the result for a `start`-origin index.

  See also:

  - rfind func
  - replace func
  Source Edit

    func find(s: string; chars: set[char]; start: Natural = 0; last = -1): int {.
        ...gcsafe, extern: "nsuFindCharSet", raises: [], tags: [], forbids: [].}

  Searches for `chars` in `s` inside range `start..last` (both ends included). If `last` is unspecified or negative, it defaults to `s.high` (the last element).

  If `s` contains none of the characters in `chars`, -1 is returned. Otherwise the index returned is relative to `s[0]`, not `start`. Subtract `start` from the result for a `start`-origin index.

  See also:

  - rfind func
  - multiReplace func
  Source Edit

    func find(s: string; sub: char; start: Natural = 0; last = -1): int {....gcsafe,
        extern: "nsuFindChar", raises: [], tags: [], forbids: [].}

  Searches for `sub` in `s` inside range `start..last` (both ends included). If `last` is unspecified or negative, it defaults to `s.high` (the last element).

  Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. Otherwise the index returned is relative to `s[0]`, not `start`. Subtract `start` from the result for a `start`-origin index.

  See also:

  - rfind func
  - replace func
  Source Edit

    func format(formatstr: string; a: varargs[string, `$`]): string {....gcsafe,
        extern: "nsuFormatVarargs", raises: [ValueError], tags: [], forbids: [].}

  This is the same as `formatstr % a` (see % func) except that it supports auto stringification.

  See also:

  - strformat module for string interpolation and formatting
  Source Edit

    func formatBiggestFloat(f: BiggestFloat; format: FloatFormatMode = ffDefault;
                            precision: range[-1 .. 32] = 16; decimalSep = '.'): string {.
        ...gcsafe, extern: "nsu$1", raises: [], tags: [], forbids: [].}

  Converts a floating point value `f` to a string.

  If `format == ffDecimal` then precision is the number of digits to be printed after the decimal point. If `format == ffScientific` then precision is the maximum number of significant digits to be printed. `precision`'s default value is the maximum number of meaningful digits after the decimal point for Nim's `biggestFloat` type.

  If `precision == -1`, it tries to format it nicely.

  Example:

      let x = 123.456
      doAssert x.formatBiggestFloat() == "123.4560000000000"
      doAssert x.formatBiggestFloat(ffDecimal, 4) == "123.4560"
      doAssert x.formatBiggestFloat(ffScientific, 2) == "1.23e+02"

  Source Edit

    func formatEng(f: BiggestFloat; precision: range[0 .. 32] = 10;
                   trim: bool = true; siPrefix: bool = false; unit: string = "";
                   decimalSep = '.'; useUnitSpace = false): string {....raises: [],
        tags: [], forbids: [].}

  Converts a floating point value `f` to a string using engineering notation.

  Numbers in of the range -1000.0<f<1000.0 will be formatted without an exponent. Numbers outside of this range will be formatted as a significand in the range -1000.0<f<1000.0 and an exponent that will always be an integer multiple of 3, corresponding with the SI prefix scale k, M, G, T etc for numbers with an absolute value greater than 1 and m, μ, n, p etc for numbers with an absolute value less than 1.

  The default configuration (`trim=true` and `precision=10`) shows the shortest form that precisely (up to a maximum of 10 decimal places) displays the value. For example, 4.100000 will be displayed as 4.1 (which is mathematically identical) whereas 4.1000003 will be displayed as 4.1000003.

  If `trim` is set to true, trailing zeros will be removed; if false, the number of digits specified by `precision` will always be shown.

  `precision` can be used to set the number of digits to be shown after the decimal point or (if `trim` is true) the maximum number of digits to be shown.

       formatEng(0, 2, trim=false) == "0.00"
       formatEng(0, 2) == "0"
       formatEng(0.053, 0) == "53e-3"
       formatEng(52731234, 2) == "52.73e6"
       formatEng(-52731234, 2) == "-52.73e6"

  If `siPrefix` is set to true, the number will be displayed with the SI prefix corresponding to the exponent. For example 4100 will be displayed as "4.1 k" instead of "4.1e3". Note that `u` is used for micro- in place of the greek letter mu (μ) as per ISO 2955. Numbers with an absolute value outside of the range 1e-18<f<1000e18 (1a<f<1000E) will be displayed with an exponent rather than an SI prefix, regardless of whether `siPrefix` is true.

  If `useUnitSpace` is true, the provided unit will be appended to the string (with a space as required by the SI standard). This behaviour is slightly different to appending the unit to the result as the location of the space is altered depending on whether there is an exponent.

       formatEng(4100, siPrefix=true, unit="V") == "4.1 kV"
       formatEng(4.1, siPrefix=true, unit="V") == "4.1 V"
       formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space
       formatEng(4100, siPrefix=true) == "4.1 k"
       formatEng(4.1, siPrefix=true, unit="") == "4.1 " # Space with unit=""
       formatEng(4100, siPrefix=true, unit="") == "4.1 k"
       formatEng(4100) == "4.1e3"
       formatEng(4100, unit="V") == "4.1e3 V"
       formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 " # Space with useUnitSpace=true

  `decimalSep` is used as the decimal separator.

  See also:

  - strformat module for string interpolation and formatting
  Source Edit

    func formatFloat(f: float; format: FloatFormatMode = ffDefault;
                     precision: range[-1 .. 32] = 16; decimalSep = '.'): string {.
        ...gcsafe, extern: "nsu$1", raises: [], tags: [], forbids: [].}

  Converts a floating point value `f` to a string.

  If `format == ffDecimal` then precision is the number of digits to be printed after the decimal point. If `format == ffScientific` then precision is the maximum number of significant digits to be printed. `precision`'s default value is the maximum number of meaningful digits after the decimal point for Nim's `float` type.

  If `precision == -1`, it tries to format it nicely.

  Example:

      let x = 123.456
      doAssert x.formatFloat() == "123.4560000000000"
      doAssert x.formatFloat(ffDecimal, 4) == "123.4560"
      doAssert x.formatFloat(ffScientific, 2) == "1.23e+02"

  Source Edit

    func formatSize(bytes: int64; decimalSep = '.'; prefix = bpIEC;
                    includeSpace = false): string {....raises: [], tags: [],
        forbids: [].}

  Rounds and formats `bytes`.

  By default, uses the IEC/ISO standard binary prefixes, so 1024 will be formatted as 1KiB. Set prefix to `bpColloquial` to use the colloquial names from the SI standard (e.g. k for 1000 being reused as 1024).

  `includeSpace` can be set to true to include the (SI preferred) space between the number and the unit (e.g. 1 KiB).

  See also:

  - strformat module for string interpolation and formatting

  Example:

      doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB"
      doAssert formatSize((2.234*1024*1024).int) == "2.233MiB"
      doAssert formatSize(4096, includeSpace = true) == "4 KiB"
      doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB"
      doAssert formatSize(4096) == "4KiB"
      doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,129MB"

  Source Edit

    func fromBin[T: SomeInteger](s: string): T

  Parses a binary integer value from a string `s`.

  If `s` is not a valid binary integer, `ValueError` is raised. `s` can have one of the following optional prefixes: `0b`, `0B`. Underscores within `s` are ignored.

  Does not check for overflow. If the value represented by `s` is too big to fit into a return type, only the value of the rightmost binary digits of `s` is returned without producing an error.

  Example:

      let s = "0b_0100_1000_1000_1000_1110_1110_1001_1001"
      doAssert fromBin[int](s) == 1216933529
      doAssert fromBin[int8](s) == 0b1001_1001'i8
      doAssert fromBin[int8](s) == -103'i8
      doAssert fromBin[uint8](s) == 153
      doAssert s.fromBin[:int16] == 0b1110_1110_1001_1001'i16
      doAssert s.fromBin[:uint64] == 1216933529'u64

  Source Edit

    func fromHex[T: SomeInteger](s: string): T

  Parses a hex integer value from a string `s`.

  If `s` is not a valid hex integer, `ValueError` is raised. `s` can have one of the following optional prefixes: `0x`, `0X`, `#`. Underscores within `s` are ignored.

  Does not check for overflow. If the value represented by `s` is too big to fit into a return type, only the value of the rightmost hex digits of `s` is returned without producing an error.

  Example:

      let s = "0x_1235_8df6"
      doAssert fromHex[int](s) == 305499638
      doAssert fromHex[int8](s) == 0xf6'i8
      doAssert fromHex[int8](s) == -10'i8
      doAssert fromHex[uint8](s) == 246'u8
      doAssert s.fromHex[:int16] == -29194'i16
      doAssert s.fromHex[:uint64] == 305499638'u64

  Source Edit

    func fromOct[T: SomeInteger](s: string): T

  Parses an octal integer value from a string `s`.

  If `s` is not a valid octal integer, `ValueError` is raised. `s` can have one of the following optional prefixes: `0o`, `0O`. Underscores within `s` are ignored.

  Does not check for overflow. If the value represented by `s` is too big to fit into a return type, only the value of the rightmost octal digits of `s` is returned without producing an error.

  Example:

      let s = "0o_123_456_777"
      doAssert fromOct[int](s) == 21913087
      doAssert fromOct[int8](s) == 0o377'i8
      doAssert fromOct[int8](s) == -1'i8
      doAssert fromOct[uint8](s) == 255'u8
      doAssert s.fromOct[:int16] == 24063'i16
      doAssert s.fromOct[:uint64] == 21913087'u64

  Source Edit

    func indent(s: string; count: Natural; padding: string = " "): string {....gcsafe,
        extern: "nsuIndent", raises: [], tags: [], forbids: [].}

  Indents each line in `s` by `count` amount of `padding`.

  Note: This does not preserve the new line characters used in `s`.

  See also:

  - align func
  - alignLeft func
  - spaces func
  - unindent func
  - dedent func

  Example:

      doAssert indent("First line\c\l and second line.", 2) ==
               "  First line\l   and second line."

  Source Edit

    func indentation(s: string): Natural {....raises: [], tags: [], forbids: [].}

  Returns the amount of indentation all lines of `s` have in common, ignoring lines that consist only of whitespace. Source Edit

    func initSkipTable(a: var SkipTable; sub: string) {....gcsafe,
        extern: "nsuInitSkipTable", raises: [], tags: [], forbids: [].}

  Initializes table `a` for efficient search of substring `sub`.

  See also:

  - initSkipTable func
  - find func
  Source Edit

    func initSkipTable(sub: string): SkipTable {.noinit, ...gcsafe,
        extern: "nsuInitNewSkipTable", raises: [], tags: [], forbids: [].}

  Returns a new table initialized for `sub`.

  See also:

  - initSkipTable func
  - find func
  Source Edit

    func insertSep(s: string; sep = '_'; digits = 3): string {....gcsafe,
        extern: "nsuInsertSep", raises: [], tags: [], forbids: [].}

  Inserts the separator `sep` after `digits` characters (default: 3) from right to left.

  Even though the algorithm works with any string `s`, it is only useful if `s` contains a number.

  Example:

      doAssert insertSep("1000000") == "1_000_000"

  Source Edit

    func intToStr(x: int; minchars: Positive = 1): string {....gcsafe,
        extern: "nsuIntToStr", raises: [], tags: [], forbids: [].}

  Converts `x` to its decimal representation.

  The resulting string will be minimally `minchars` characters long. This is achieved by adding leading zeros.

  Example:

      doAssert intToStr(1984) == "1984"
      doAssert intToStr(1984, 6) == "001984"

  Source Edit

    func isAlphaAscii(c: char): bool {....gcsafe, extern: "nsuIsAlphaAsciiChar",
                                       raises: [], tags: [], forbids: [].}

  Checks whether or not character `c` is alphabetical.

  This checks a-z, A-Z ASCII characters only. Use Unicode module for UTF-8 support.

  Example:

      doAssert isAlphaAscii('e') == true
      doAssert isAlphaAscii('E') == true
      doAssert isAlphaAscii('8') == false

  Source Edit

    func isAlphaNumeric(c: char): bool {....gcsafe, extern: "nsuIsAlphaNumericChar",
                                         raises: [], tags: [], forbids: [].}

  Checks whether or not `c` is alphanumeric.

  This checks a-z, A-Z, 0-9 ASCII characters only.

  Example:

      doAssert isAlphaNumeric('n') == true
      doAssert isAlphaNumeric('8') == true
      doAssert isAlphaNumeric(' ') == false

  Source Edit

    func isDigit(c: char): bool {....gcsafe, extern: "nsuIsDigitChar", raises: [],
                                  tags: [], forbids: [].}

  Checks whether or not `c` is a number.

  This checks 0-9 ASCII characters only.

  Example:

      doAssert isDigit('n') == false
      doAssert isDigit('8') == true

  Source Edit

    func isEmptyOrWhitespace(s: string): bool {....gcsafe,
        extern: "nsuIsEmptyOrWhitespace", raises: [], tags: [], forbids: [].}

  Checks if `s` is empty or consists entirely of whitespace characters. Source Edit

    func isLowerAscii(c: char): bool {....gcsafe, extern: "nsuIsLowerAsciiChar",
                                       raises: [], tags: [], forbids: [].}

  Checks whether or not `c` is a lower case character.

  This checks ASCII characters only. Use Unicode module for UTF-8 support.

  See also:

  - toLowerAscii func

  Example:

      doAssert isLowerAscii('e') == true
      doAssert isLowerAscii('E') == false
      doAssert isLowerAscii('7') == false

  Source Edit

    func isSpaceAscii(c: char): bool {....gcsafe, extern: "nsuIsSpaceAsciiChar",
                                       raises: [], tags: [], forbids: [].}

  Checks whether or not `c` is a whitespace character.

  Example:

      doAssert isSpaceAscii('n') == false
      doAssert isSpaceAscii(' ') == true
      doAssert isSpaceAscii('\t') == true

  Source Edit

    func isUpperAscii(c: char): bool {....gcsafe, extern: "nsuIsUpperAsciiChar",
                                       raises: [], tags: [], forbids: [].}

  Checks whether or not `c` is an upper case character.

  This checks ASCII characters only. Use Unicode module for UTF-8 support.

  See also:

  - toUpperAscii func

  Example:

      doAssert isUpperAscii('e') == false
      doAssert isUpperAscii('E') == true
      doAssert isUpperAscii('7') == false

  Source Edit

    func join(a: openArray[string]; sep: string = ""): string {....gcsafe,
        extern: "nsuJoinSep", raises: [], tags: [], forbids: [].}

  Concatenates all strings in the container `a`, separating them with `sep`.

  Example:

      doAssert join(["A", "B", "Conclusion"], " -> ") == "A -> B -> Conclusion"

  Source Edit

    proc join[T: not string](a: openArray[T]; sep: string = ""): string

  Converts all elements in the container `a` to strings using `$`, and concatenates them with `sep`.

  Example:

      doAssert join([1, 2, 3], " -> ") == "1 -> 2 -> 3"

  Source Edit

    func multiReplace(s: openArray[char]; replacements: varargs[(set[char], char)]): string {.
        noinit, ...raises: [], tags: [], forbids: [].}

  Performs multiple character replacements in a single pass through the input.

  `multiReplace` scans the input `s` from left to right and replaces characters based on character sets, applying the first matching replacement at each position. Useful for sanitizing or transforming strings with predefined character mappings.

  The order of the `replacements` matters:

  - First matching replacement is applied
  - Subsequent replacements are not considered for the same character

  See also:

  - multiReplace(s: string; replacements: varargs[(string, string)]),

  Example:

      const WinSanitationRules = [
        ({'\0'..'\31'}, ' '),
        ({'"'}, '\''),
        ({'/', '\\', ':', '|'}, '-'),
        ({'*', '?', '<', '>'}, '_'),
      ]
      # Sanitize a filename with Windows-incompatible characters
      const file = "a/file:with?invalid*chars.txt"
      doAssert file.multiReplace(WinSanitationRules) == "a-file-with_invalid_chars.txt"

  Source Edit

    func multiReplace(s: string; replacements: varargs[(string, string)]): string {.
        ...raises: [], tags: [], forbids: [].}

  Same as replace, but specialized for doing multiple replacements in a single pass through the input string.

  `multiReplace` scans the input string from left to right and replaces the matching substrings in the same order as passed in the argument list.

  The implications of the order of scanning the string and matching the replacements:

  - In case of multiple matches at a given position, the earliest replacement is applied.
  - Overlaps are not handled. After performing a replacement, the scan continues from the character after the matched substring. If the resulting string then contains a possible match starting in a newly placed substring, the additional replacement is not performed.

  If the resulting string is not longer than the original input string, only a single memory allocation is required.

  Example:

      # Swapping occurrences of 'a' and 'b':
      doAssert multireplace("abba", [("a", "b"), ("b", "a")]) == "baab"

      # The second replacement ("ab") is matched and performed first, the scan then
      # continues from 'c', so the "bc" replacement is never matched and thus skipped.
      doAssert multireplace("abc", [("bc", "x"), ("ab", "_b")]) == "_bc"

  Source Edit

    func nimIdentNormalize(s: string): string {....raises: [], tags: [], forbids: [].}

  Normalizes the string `s` as a Nim identifier.

  That means to convert to lower case and remove any '_' on all characters except first one.

  Warning: Backticks (`) are not handled: they remain as is and spaces are preserved. See nimIdentBackticksNormalize for an alternative approach.

  Example:

      doAssert nimIdentNormalize("Foo_bar") == "Foobar"

  Source Edit

    func normalize(s: string): string {....gcsafe, extern: "nsuNormalize", raises: [],
                                        tags: [], forbids: [].}

  Normalizes the string `s`.

  That means to convert it to lower case and remove any '_'. This should NOT be used to normalize Nim identifier names.

  See also:

  - toLowerAscii func

  Example:

      doAssert normalize("Foo_bar") == "foobar"
      doAssert normalize("Foo Bar") == "foo bar"

  Source Edit

    func parseBiggestInt(s: string): BiggestInt {....gcsafe,
        extern: "nsuParseBiggestInt", raises: [ValueError], tags: [], forbids: [].}

  Parses a decimal integer value contained in `s`.

  If `s` is not a valid integer, `ValueError` is raised.

  Source Edit

    func parseBiggestUInt(s: string): BiggestUInt {....gcsafe,
        extern: "nsuParseBiggestUInt", raises: [ValueError], tags: [], forbids: [].}

  Parses a decimal unsigned integer value contained in `s`.

  If `s` is not a valid integer, `ValueError` is raised.

  Source Edit

    func parseBinInt(s: string): int {....gcsafe, extern: "nsuParseBinInt",
                                       raises: [ValueError], tags: [], forbids: [].}

  Parses a binary integer value contained in `s`.

  If `s` is not a valid binary integer, `ValueError` is raised. `s` can have one of the following optional prefixes: `0b`, `0B`. Underscores within `s` are ignored.

  Example:

      let
        a = "0b11_0101"
        b = "111"
      doAssert a.parseBinInt() == 53
      doAssert b.parseBinInt() == 7

  Source Edit

    func parseBool(s: string): bool {....raises: [ValueError], tags: [], forbids: [].}

  Parses a value into a `bool`.

  If `s` is one of the following values: `y, yes, true, 1, on`, then returns `true`. If `s` is one of the following values: `n, no, false, 0, off`, then returns `false`. If `s` is something else a `ValueError` exception is raised.

  Example:

      let a = "n"
      doAssert parseBool(a) == false

  Source Edit

    func parseEnum[T: enum](s: string): T

  Parses an enum `T`. This errors at compile time, if the given enum type contains multiple fields with the same string value.

  Raises `ValueError` for an invalid value in `s`. The comparison is done in a style insensitive way (first letter is still case-sensitive).

  Example:

      type
        MyEnum = enum
          first = "1st",
          second,
          third = "3rd"

      doAssert parseEnum[MyEnum]("1_st") == first
      doAssert parseEnum[MyEnum]("second") == second
      doAssertRaises(ValueError):
        echo parseEnum[MyEnum]("third")

  Source Edit

    func parseEnum[T: enum](s: string; default: T): T

  Parses an enum `T`. This errors at compile time, if the given enum type contains multiple fields with the same string value.

  Uses `default` for an invalid value in `s`. The comparison is done in a style insensitive way (first letter is still case-sensitive).

  Example:

      type
        MyEnum = enum
          first = "1st",
          second,
          third = "3rd"

      doAssert parseEnum[MyEnum]("1_st") == first
      doAssert parseEnum[MyEnum]("second") == second
      doAssert parseEnum[MyEnum]("last", third) == third

  Source Edit

    func parseFloat(s: string): float {....gcsafe, extern: "nsuParseFloat",
                                        raises: [ValueError], tags: [], forbids: [].}

  Parses a decimal floating point value contained in `s`.

  If `s` is not a valid floating point number, `ValueError` is raised. `NAN`, `INF`, `-INF` are also supported (case insensitive comparison).

  Example:

      doAssert parseFloat("3.14") == 3.14
      doAssert parseFloat("inf") == 1.0/0

  Source Edit

    func parseHexInt(s: string): int {....gcsafe, extern: "nsuParseHexInt",
                                       raises: [ValueError], tags: [], forbids: [].}

  Parses a hexadecimal integer value contained in `s`.

  If `s` is not a valid hex integer, `ValueError` is raised. `s` can have one of the following optional prefixes: `0x`, `0X`, `#`. Underscores within `s` are ignored.

  Source Edit

    func parseHexStr(s: string): string {....gcsafe, extern: "nsuParseHexStr",
                                          raises: [ValueError], tags: [],
                                          forbids: [].}

  Converts hex-encoded string to byte string, e.g.:

  Raises `ValueError` for an invalid hex values. The comparison is case-insensitive.

  See also:

  - toHex func for the reverse operation

  Example:

      let
        a = "41"
        b = "3161"
        c = "00ff"
      doAssert parseHexStr(a) == "A"
      doAssert parseHexStr(b) == "1a"
      doAssert parseHexStr(c) == "\0\255"

  Source Edit

    func parseInt(s: string): int {....gcsafe, extern: "nsuParseInt",
                                    raises: [ValueError], tags: [], forbids: [].}

  Parses a decimal integer value contained in `s`.

  If `s` is not a valid integer, `ValueError` is raised.

  Example:

      doAssert parseInt("-0042") == -42

  Source Edit

    func parseOctInt(s: string): int {....gcsafe, extern: "nsuParseOctInt",
                                       raises: [ValueError], tags: [], forbids: [].}

  Parses an octal integer value contained in `s`.

  If `s` is not a valid oct integer, `ValueError` is raised. `s` can have one of the following optional prefixes: `0o`, `0O`. Underscores within `s` are ignored.

  Source Edit

    func parseUInt(s: string): uint {....gcsafe, extern: "nsuParseUInt",
                                      raises: [ValueError], tags: [], forbids: [].}

  Parses a decimal unsigned integer value contained in `s`.

  If `s` is not a valid integer, `ValueError` is raised.

  Source Edit

    func removePrefix(s: var string; c: char) {....gcsafe,
        extern: "nsuRemovePrefixChar", raises: [], tags: [], forbids: [].}

  Removes all occurrences of a single character (in-place) from the start of a string.

  See also:

  - removeSuffix func
  - startsWith func

  Example:

      var ident = "pControl"
      ident.removePrefix('p')
      doAssert ident == "Control"

  Source Edit

    func removePrefix(s: var string; chars: set[char] = Newlines) {....gcsafe,
        extern: "nsuRemovePrefixCharSet", raises: [], tags: [], forbids: [].}

  Removes all characters from `chars` from the start of the string `s` (in-place).

  See also:

  - removeSuffix func

  Example:

      var userInput = "\r\n*~Hello World!"
      userInput.removePrefix
      doAssert userInput == "*~Hello World!"
      userInput.removePrefix({'~', '*'})
      doAssert userInput == "Hello World!"

      var otherInput = "?!?Hello!?!"
      otherInput.removePrefix({'!', '?'})
      doAssert otherInput == "Hello!?!"

  Source Edit

    func removePrefix(s: var string; prefix: string) {....gcsafe,
        extern: "nsuRemovePrefixString", raises: [], tags: [], forbids: [].}

  Remove the first matching prefix (in-place) from a string.

  See also:

  - removeSuffix func
  - startsWith func

  Example:

      var answers = "yesyes"
      answers.removePrefix("yes")
      doAssert answers == "yes"

  Source Edit

    func removeSuffix(s: var string; c: char) {....gcsafe,
        extern: "nsuRemoveSuffixChar", raises: [], tags: [], forbids: [].}

  Removes all occurrences of a single character (in-place) from the end of a string.

  See also:

  - removePrefix func
  - endsWith func

  Example:

      var table = "users"
      table.removeSuffix('s')
      doAssert table == "user"

      var dots = "Trailing dots......."
      dots.removeSuffix('.')
      doAssert dots == "Trailing dots"

  Source Edit

    func removeSuffix(s: var string; chars: set[char] = Newlines) {....gcsafe,
        extern: "nsuRemoveSuffixCharSet", raises: [], tags: [], forbids: [].}

  Removes all characters from `chars` from the end of the string `s` (in-place).

  See also:

  - removePrefix func

  Example:

      var userInput = "Hello World!*~\r\n"
      userInput.removeSuffix
      doAssert userInput == "Hello World!*~"
      userInput.removeSuffix({'~', '*'})
      doAssert userInput == "Hello World!"

      var otherInput = "Hello!?!"
      otherInput.removeSuffix({'!', '?'})
      doAssert otherInput == "Hello"

  Source Edit

    func removeSuffix(s: var string; suffix: string) {....gcsafe,
        extern: "nsuRemoveSuffixString", raises: [], tags: [], forbids: [].}

  Remove the first matching suffix (in-place) from a string.

  See also:

  - removePrefix func
  - endsWith func

  Example:

      var answers = "yeses"
      answers.removeSuffix("es")
      doAssert answers == "yes"

  Source Edit

    func repeat(c: char; count: Natural): string {....gcsafe, extern: "nsuRepeatChar",
        raises: [], tags: [], forbids: [].}

  Returns a string of length `count` consisting only of the character `c`.

  Example:

      let a = 'z'
      doAssert a.repeat(5) == "zzzzz"

  Source Edit

    func repeat(s: string; n: Natural): string {....gcsafe, extern: "nsuRepeatStr",
        raises: [], tags: [], forbids: [].}

  Returns string `s` concatenated `n` times.

  Example:

      doAssert "+ foo +".repeat(3) == "+ foo ++ foo ++ foo +"

  Source Edit

    func replace(s, sub: string; by = ""): string {....gcsafe, extern: "nsuReplaceStr",
        raises: [], tags: [], forbids: [].}

  Replaces every occurrence of the string `sub` in `s` with the string `by`.

  See also:

  - find func
  - replace func for replacing single characters
  - replaceWord func
  - multiReplace func for substrings
  - multiReplace func for single characters
  Source Edit

    func replace(s: string; sub, by: char): string {....gcsafe,
        extern: "nsuReplaceChar", raises: [], tags: [], forbids: [].}

  Replaces every occurrence of the character `sub` in `s` with the character `by`.

  Optimized version of replace for characters.

  See also:

  - find func
  - replaceWord func
  - multiReplace func for substrings
  - multiReplace func for single characters
  Source Edit

    func replaceWord(s, sub: string; by = ""): string {....gcsafe,
        extern: "nsuReplaceWord", raises: [], tags: [], forbids: [].}

  Replaces every occurrence of the string `sub` in `s` with the string `by`.

  Each occurrence of `sub` has to be surrounded by word boundaries (comparable to `\b` in regular expressions), otherwise it is not replaced.

  Source Edit

    func rfind(s, sub: string; start: Natural = 0; last = -1): int {....gcsafe,
        extern: "nsuRFindStr", raises: [], tags: [], forbids: [].}

  Searches for `sub` in `s` inside range `start..last` (both ends included) included) in reverse -- starting at high indexes and moving lower to the first character or `start`. If `last` is unspecified, it defaults to `s.high` (the last element).

  Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. Otherwise the index returned is relative to `s[0]`, not `start`. Subtract `start` from the result for a `start`-origin index.

  See also:

  - find func
  Source Edit

    func rfind(s: string; chars: set[char]; start: Natural = 0; last = -1): int {.
        ...gcsafe, extern: "nsuRFindCharSet", raises: [], tags: [], forbids: [].}

  Searches for `chars` in `s` inside range `start..last` (both ends included) in reverse -- starting at high indexes and moving lower to the first character or `start`. If `last` is unspecified, it defaults to `s.high` (the last element).

  If `s` contains none of the characters in `chars`, -1 is returned. Otherwise the index returned is relative to `s[0]`, not `start`. Subtract `start` from the result for a `start`-origin index.

  See also:

  - find func
  Source Edit

    func rfind(s: string; sub: char; start: Natural = 0; last = -1): int {....gcsafe,
        extern: "nsuRFindChar", raises: [], tags: [], forbids: [].}

  Searches for `sub` in `s` inside range `start..last` (both ends included) in reverse -- starting at high indexes and moving lower to the first character or `start`. If `last` is unspecified, it defaults to `s.high` (the last element).

  Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. Otherwise the index returned is relative to `s[0]`, not `start`. Subtract `start` from the result for a `start`-origin index.

  See also:

  - find func
  Source Edit

    func rsplit(s: string; sep: char; maxsplit: int = -1): seq[string] {....gcsafe,
        extern: "nsuRSplitChar", raises: [], tags: [], forbids: [].}

  The same as the rsplit iterator, but is a func that returns a sequence of substrings in original order.

  A possible common use case for `rsplit` is path manipulation, particularly on systems that don't use a common delimiter.

  For example, if a system had `#` as a delimiter, you could do the following to get the tail of the path:

      var tailSplit = rsplit("Root#Object#Method#Index", '#', maxsplit=1)

  Results in `tailSplit` containing:

      @["Root#Object#Method", "Index"]

  See also:

  - rsplit iterator
  - split func
  - splitLines func
  - splitWhitespace func
  Source Edit

    func rsplit(s: string; sep: string; maxsplit: int = -1): seq[string] {....gcsafe,
        extern: "nsuRSplitString", raises: [], tags: [], forbids: [].}

  The same as the rsplit iterator, but is a func that returns a sequence of substrings in original order.

  A possible common use case for `rsplit` is path manipulation, particularly on systems that don't use a common delimiter.

  For example, if a system had `#` as a delimiter, you could do the following to get the tail of the path:

      var tailSplit = rsplit("Root#Object#Method#Index", "#", maxsplit=1)

  Results in `tailSplit` containing:

      @["Root#Object#Method", "Index"]

  Note: Empty separator string results in returning an original string, following the interpretation "split by no element".

  See also:

  - rsplit iterator
  - split func
  - splitLines func
  - splitWhitespace func

  Example:

      doAssert "a  largely    spaced sentence".rsplit(" ", maxsplit = 1) == @[
          "a  largely    spaced", "sentence"]
      doAssert "a,b,c".rsplit(",") == @["a", "b", "c"]
      doAssert "a man a plan a canal panama".rsplit("a ") == @["", "man ",
          "plan ", "canal panama"]
      doAssert "".rsplit("Elon Musk") == @[""]
      doAssert "a  largely    spaced sentence".rsplit(" ") == @["a", "",
          "largely", "", "", "", "spaced", "sentence"]
      doAssert "empty sep returns unsplit s".rsplit("") == @["empty sep returns unsplit s"]

  Source Edit

    func rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[
        string] {....gcsafe, extern: "nsuRSplitCharSet", raises: [], tags: [],
                  forbids: [].}

  The same as the rsplit iterator, but is a func that returns a sequence of substrings in original order.

  A possible common use case for `rsplit` is path manipulation, particularly on systems that don't use a common delimiter.

  For example, if a system had `#` as a delimiter, you could do the following to get the tail of the path:

      var tailSplit = rsplit("Root#Object#Method#Index", {'#'}, maxsplit=1)

  Results in `tailSplit` containing:

      @["Root#Object#Method", "Index"]

  Note: Empty separator set results in returning an original string, following the interpretation "split by no element".

  See also:

  - rsplit iterator
  - split func
  - splitLines func
  - splitWhitespace func
  Source Edit

    func spaces(n: Natural): string {.inline, ...raises: [], tags: [], forbids: [].}

  Returns a string with `n` space characters. You can use this func to left align strings.

  See also:

  - align func
  - alignLeft func
  - indent func
  - center func

  Example:

      let
        width = 15
        text1 = "Hello user!"
        text2 = "This is a very long string"
      doAssert text1 & spaces(max(0, width - text1.len)) & "|" ==
               "Hello user!    |"
      doAssert text2 & spaces(max(0, width - text2.len)) & "|" ==
               "This is a very long string|"

  Source Edit

    func split(s: string; sep: char; maxsplit: int = -1): seq[string] {....gcsafe,
        extern: "nsuSplitChar", raises: [], tags: [], forbids: [].}

  The same as the split iterator (see its documentation), but is a func that returns a sequence of substrings.

  See also:

  - split iterator
  - rsplit func
  - splitLines func
  - splitWhitespace func

  Example:

      doAssert "a,b,c".split(',') == @["a", "b", "c"]
      doAssert "".split(' ') == @[""]

  Source Edit

    func split(s: string; sep: string; maxsplit: int = -1): seq[string] {....gcsafe,
        extern: "nsuSplitString", raises: [], tags: [], forbids: [].}

  Splits the string `s` into substrings using a string separator.

  Substrings are separated by the string `sep`. This is a wrapper around the split iterator.

  Note: Empty separator string results in returning an original string, following the interpretation "split by no element".

  See also:

  - split iterator
  - rsplit func
  - splitLines func
  - splitWhitespace func

  Example:

      doAssert "a,b,c".split(",") == @["a", "b", "c"]
      doAssert "a man a plan a canal panama".split("a ") == @["", "man ", "plan ", "canal panama"]
      doAssert "".split("Elon Musk") == @[""]
      doAssert "a  largely    spaced sentence".split(" ") == @["a", "", "largely",
          "", "", "", "spaced", "sentence"]
      doAssert "a  largely    spaced sentence".split(" ", maxsplit = 1) == @["a", " largely    spaced sentence"]
      doAssert "empty sep returns unsplit s".split("") == @["empty sep returns unsplit s"]

  Source Edit

    func split(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[
        string] {....gcsafe, extern: "nsuSplitCharSet", raises: [], tags: [],
                  forbids: [].}

  The same as the split iterator (see its documentation), but is a func that returns a sequence of substrings.
  Note: Empty separator set results in returning an original string, following the interpretation "split by no element".

  See also:

  - split iterator
  - rsplit func
  - splitLines func
  - splitWhitespace func

  Example:

      doAssert "a,b;c".split({',', ';'}) == @["a", "b", "c"]
      doAssert "".split({' '}) == @[""]
      doAssert "empty seps return unsplit s".split({}) == @["empty seps return unsplit s"]

  Source Edit

    func splitLines(s: string; keepEol = false): seq[string] {....gcsafe,
        extern: "nsuSplitLines", raises: [], tags: [], forbids: [].}

  The same as the splitLines iterator (see its documentation), but is a func that returns a sequence of substrings.

  See also:

  - splitLines iterator
  - splitWhitespace func
  - countLines func
  Source Edit

    func splitWhitespace(s: string; maxsplit: int = -1): seq[string] {....gcsafe,
        extern: "nsuSplitWhitespace", raises: [], tags: [], forbids: [].}

  The same as the splitWhitespace iterator (see its documentation), but is a func that returns a sequence of substrings.

  See also:

  - splitWhitespace iterator
  - splitLines func
  Source Edit

    func startsWith(s, prefix: string): bool {....gcsafe, extern: "nsuStartsWith",
        raises: [], tags: [], forbids: [].}

  Returns true if `s` starts with string `prefix`.

  If `prefix == ""` true is returned.

  See also:

  - endsWith func
  - continuesWith func
  - removePrefix func

  Example:

      let a = "abracadabra"
      doAssert a.startsWith("abra") == true
      doAssert a.startsWith("bra") == false

  Source Edit

    func startsWith(s: string; prefix: char): bool {.inline, ...raises: [], tags: [],
        forbids: [].}

  Returns true if `s` starts with character `prefix`.

  See also:

  - endsWith func
  - continuesWith func
  - removePrefix func

  Example:

      let a = "abracadabra"
      doAssert a.startsWith('a') == true
      doAssert a.startsWith('b') == false

  Source Edit

    func strip(s: string; leading = true; trailing = true;
               chars: set[char] = Whitespace): string {....gcsafe, extern: "nsuStrip",
        raises: [], tags: [], forbids: [].}

  Strips leading or trailing `chars` (default: whitespace characters) from `s` and returns the resulting string.

  If `leading` is true (default), leading `chars` are stripped. If `trailing` is true (default), trailing `chars` are stripped. If both are false, the string is returned unchanged.

  See also:

  - strip proc Inplace version.
  - stripLineEnd func

  Example:

      let a = "  vhellov   "
      let b = strip(a)
      doAssert b == "vhellov"

      doAssert a.strip(leading = false) == "  vhellov"
      doAssert a.strip(trailing = false) == "vhellov   "

      doAssert b.strip(chars = {'v'}) == "hello"
      doAssert b.strip(leading = false, chars = {'v'}) == "vhello"

      let c = "blaXbla"
      doAssert c.strip(chars = {'b', 'a'}) == "laXbl"
      doAssert c.strip(chars = {'b', 'a', 'l'}) == "X"

  Source Edit

    func stripLineEnd(s: var string) {....raises: [], tags: [], forbids: [].}

  Strips one of these suffixes from `s` in-place: `\r, \n, \r\n, \f, \v` (at most once instance). For example, can be useful in conjunction with `osproc.execCmdEx`. aka: chomp

  Example:

      var s = "foo\n\n"
      s.stripLineEnd
      doAssert s == "foo\n"
      s = "foo\r\n"
      s.stripLineEnd
      doAssert s == "foo"

  Source Edit

    func toBin(x: BiggestInt; len: Positive): string {....gcsafe, extern: "nsuToBin",
        raises: [], tags: [], forbids: [].}

  Converts `x` into its binary representation.

  The resulting string is always `len` characters long. No leading `0b` prefix is generated.

  Example:

      let
        a = 29
        b = 257
      doAssert a.toBin(8) == "00011101"
      doAssert b.toBin(8) == "00000001"
      doAssert b.toBin(9) == "100000001"

  Source Edit

    func toHex(s: string): string {....gcsafe, raises: [], tags: [], forbids: [].}

  Converts a bytes string to its hexadecimal representation.

  The output is twice the input long. No prefix like `0x` is generated.

  See also:

  - parseHexStr func for the reverse operation

  Example:

      let
        a = "1"
        b = "A"
        c = "\0\255"
      doAssert a.toHex() == "31"
      doAssert b.toHex() == "41"
      doAssert c.toHex() == "00FF"

  Source Edit

    func toHex[T: SomeInteger](x: T): string

  Shortcut for `toHex(x, T.sizeof * 2)`

  Example:

      doAssert toHex(1984'i64) == "00000000000007C0"
      doAssert toHex(1984'i16) == "07C0"

  Source Edit

    func toHex[T: SomeInteger](x: T; len: Positive): string

  Converts `x` to its hexadecimal representation.

  The resulting string will be exactly `len` characters long. No prefix like `0x` is generated. `x` is treated as an unsigned value.

  Example:

      let
        a = 62'u64
        b = 4097'u64
      doAssert a.toHex(3) == "03E"
      doAssert b.toHex(3) == "001"
      doAssert b.toHex(4) == "1001"
      doAssert toHex(62, 3) == "03E"
      doAssert toHex(-8, 6) == "FFFFF8"

  Source Edit

    func toLowerAscii(c: char): char {....gcsafe, extern: "nsuToLowerAsciiChar",
                                       raises: [], tags: [], forbids: [].}

  Returns the lower case version of character `c`.

  This works only for the letters `A-Z`. See unicode.toLower for a version that works for any Unicode character.

  See also:

  - isLowerAscii func
  - toLowerAscii func for converting a string

  Example:

      doAssert toLowerAscii('A') == 'a'
      doAssert toLowerAscii('e') == 'e'

  Source Edit

    func toLowerAscii(s: string): string {....gcsafe, extern: "nsuToLowerAsciiStr",
                                           raises: [], tags: [], forbids: [].}

  Converts string `s` into lower case.

  This works only for the letters `A-Z`. See unicode.toLower for a version that works for any Unicode character.

  See also:

  - normalize func

  Example:

      doAssert toLowerAscii("FooBar!") == "foobar!"

  Source Edit

    func toOct(x: BiggestInt; len: Positive): string {....gcsafe, extern: "nsuToOct",
        raises: [], tags: [], forbids: [].}

  Converts `x` into its octal representation.

  The resulting string is always `len` characters long. No leading `0o` prefix is generated.

  Do not confuse it with toOctal func.

  Example:

      let
        a = 62
        b = 513
      doAssert a.toOct(3) == "076"
      doAssert b.toOct(3) == "001"
      doAssert b.toOct(5) == "01001"

  Source Edit

    func toOctal(c: char): string {....gcsafe, extern: "nsuToOctal", raises: [],
                                    tags: [], forbids: [].}

  Converts a character `c` to its octal representation.

  The resulting string may not have a leading zero. Its length is always exactly 3.

  Do not confuse it with toOct func.

  Example:

      doAssert toOctal('1') == "061"
      doAssert toOctal('A') == "101"
      doAssert toOctal('a') == "141"
      doAssert toOctal('!') == "041"

  Source Edit

    func toUpperAscii(c: char): char {....gcsafe, extern: "nsuToUpperAsciiChar",
                                       raises: [], tags: [], forbids: [].}

  Converts character `c` into upper case.

  This works only for the letters `A-Z`. See unicode.toUpper for a version that works for any Unicode character.

  See also:

  - isUpperAscii func
  - toUpperAscii func for converting a string
  - capitalizeAscii func

  Example:

      doAssert toUpperAscii('a') == 'A'
      doAssert toUpperAscii('E') == 'E'

  Source Edit

    func toUpperAscii(s: string): string {....gcsafe, extern: "nsuToUpperAsciiStr",
                                           raises: [], tags: [], forbids: [].}

  Converts string `s` into upper case.

  This works only for the letters `A-Z`. See unicode.toUpper for a version that works for any Unicode character.

  See also:

  - capitalizeAscii func

  Example:

      doAssert toUpperAscii("FooBar!") == "FOOBAR!"

  Source Edit

    func trimZeros(x: var string; decimalSep = '.') {....raises: [], tags: [],
        forbids: [].}

  Trim trailing zeros from a formatted floating point value `x` (must be declared as `var`).

  This modifies `x` itself, it does not return a copy.

  Example:

      var x = "123.456000000"
      x.trimZeros()
      doAssert x == "123.456"

  Source Edit

    func unescape(s: string; prefix = "\""; suffix = "\""): string {....gcsafe,
        extern: "nsuUnescape", raises: [ValueError], tags: [], forbids: [].}

  Unescapes a string `s`.

  This complements escape func as it performs the opposite operations.

  If `s` does not begin with `prefix` and end with `suffix` a ValueError exception will be raised.

  Source Edit

    func unindent(s: string; count: Natural = int.high; padding: string = " "): string {.
        ...gcsafe, extern: "nsuUnindent", raises: [], tags: [], forbids: [].}

  Unindents each line in `s` by `count` amount of `padding`.

  Note: This does not preserve the new line characters used in `s`.

  See also:

  - dedent func
  - align func
  - alignLeft func
  - spaces func
  - indent func

  Example:

      let x = """
            Hello
              There
          """.unindent()

      doAssert x == "Hello\nThere\n"

  Source Edit

    func validIdentifier(s: string): bool {....gcsafe, extern: "nsuValidIdentifier",
                                            raises: [], tags: [], forbids: [].}

  Returns true if `s` is a valid identifier.

  A valid identifier starts with a character of the set `IdentStartChars` and is followed by any number of characters of the set `IdentChars`.

  Example:

      doAssert "abc_def08".validIdentifier

  Source Edit

# Iterators

    iterator rsplit(s: string; sep: char; maxsplit: int = -1): string {....raises: [],
        tags: [], forbids: [].}

  Splits the string `s` into substrings from the right using a string separator. Works exactly the same as split iterator except in reverse order.

      for piece in "foo:bar".rsplit(':'):
        echo piece

  Results in:

      "bar"
      "foo"

  Substrings are separated from the right by the char `sep`.

  See also:

  - split iterator
  - splitLines iterator
  - splitWhitespace iterator
  - rsplit func
  Source Edit

    iterator rsplit(s: string; sep: string; maxsplit: int = -1;
                    keepSeparators: bool = false): string {....raises: [], tags: [],
        forbids: [].}

  Splits the string `s` into substrings from the right using a string separator. Works exactly the same as split iterator except in reverse order.

      for piece in "foothebar".rsplit("the"):
        echo piece

  Results in:

      "bar"
      "foo"

  Substrings are separated from the right by the string `sep`

  Note: Empty separator string results in returning an original string, following the interpretation "split by no element".

  See also:

  - split iterator
  - splitLines iterator
  - splitWhitespace iterator
  - rsplit func
  Source Edit

    iterator rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): string {.
        ...raises: [], tags: [], forbids: [].}

  Splits the string `s` into substrings from the right using a string separator. Works exactly the same as split iterator except in reverse order.

      for piece in "foo bar".rsplit(WhiteSpace):
        echo piece

  Results in:

      "bar"
      "foo"

  Substrings are separated from the right by the set of chars `seps`

  Note: Empty separator set results in returning an original string, following the interpretation "split by no element".

  See also:

  - split iterator
  - splitLines iterator
  - splitWhitespace iterator
  - rsplit func
  Source Edit

    iterator split(s: string; sep: char; maxsplit: int = -1): string {....raises: [],
        tags: [], forbids: [].}

  Splits the string `s` into substrings using a single separator.

  Substrings are separated by the character `sep`. The code:

      for word in split(";;this;is;an;;example;;;", ';'):
        writeLine(stdout, word)

  Results in:

      ""
      ""
      "this"
      "is"
      "an"
      ""
      "example"
      ""
      ""
      ""

  See also:

  - rsplit iterator
  - splitLines iterator
  - splitWhitespace iterator
  - split func
  Source Edit

    iterator split(s: string; sep: string; maxsplit: int = -1): string {....raises: [],
        tags: [], forbids: [].}

  Splits the string `s` into substrings using a string separator.

  Substrings are separated by the string `sep`. The code:

      for word in split("thisDATAisDATAcorrupted", "DATA"):
        writeLine(stdout, word)

  Results in:

      "this"
      "is"
      "corrupted"

  Note: Empty separator string results in returning an original string, following the interpretation "split by no element".

  See also:

  - rsplit iterator
  - splitLines iterator
  - splitWhitespace iterator
  - split func
  Source Edit

    iterator split(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): string {.
        ...raises: [], tags: [], forbids: [].}

  Splits the string `s` into substrings using a group of separators.

  Substrings are separated by a substring containing only `seps`.

      for word in split("this\lis an\texample"):
        writeLine(stdout, word)

  ...generates this output:

      "this"
      "is"
      "an"
      "example"

  And the following code:

      for word in split("this:is;an$example", {';', ':', '$'}):
        writeLine(stdout, word)

  ...produces the same output as the first example. The code:

      let date = "2012-11-20T22:08:08.398990"
      let separators = {' ', '-', ':', 'T'}
      for number in split(date, separators):
        writeLine(stdout, number)

  ...results in:

      "2012"
      "11"
      "20"
      "22"
      "08"
      "08.398990"

  Note: Empty separator set results in returning an original string, following the interpretation "split by no element".

  See also:

  - rsplit iterator
  - splitLines iterator
  - splitWhitespace iterator
  - split func
  Source Edit

    iterator splitLines(s: string; keepEol = false): string {....raises: [], tags: [],
        forbids: [].}

  Splits the string `s` into its containing lines.

  Every character literal newline combination (CR, LF, CR-LF) is supported. The result strings contain no trailing end of line characters unless the parameter `keepEol` is set to `true`.

  Example:

      for line in splitLines("\nthis\nis\nan\n\nexample\n"):
        writeLine(stdout, line)

  Results in:

      ""
      "this"
      "is"
      "an"
      ""
      "example"
      ""

  See also:

  - splitWhitespace iterator
  - splitLines func
  Source Edit

    iterator splitWhitespace(s: string; maxsplit: int = -1): string {....raises: [],
        tags: [], forbids: [].}

  Splits the string `s` at whitespace stripping leading and trailing whitespace if necessary. If `maxsplit` is specified and is positive, no more than `maxsplit` splits is made.

  The following code:

      let s = "  foo \t bar  baz  "
      for ms in [-1, 1, 2, 3]:
        echo "------ maxsplit = ", ms, ":"
        for item in s.splitWhitespace(maxsplit=ms):
          echo '"', item, '"'

  ...results in:

      ------ maxsplit = -1:
      "foo"
      "bar"
      "baz"
      ------ maxsplit = 1:
      "foo"
      "bar  baz  "
      ------ maxsplit = 2:
      "foo"
      "bar"
      "baz  "
      ------ maxsplit = 3:
      "foo"
      "bar"
      "baz"

  See also:

  - splitLines iterator
  - splitWhitespace func
  Source Edit

    iterator tokenize(s: string; seps: set[char] = Whitespace): tuple[token: string,
        isSep: bool] {....raises: [], tags: [], forbids: [].}

  Tokenizes the string `s` into substrings.

  Substrings are separated by a substring containing only `seps`. Example:

      for word in tokenize("  this is an  example  "):
        writeLine(stdout, word)

  Results in:

      ("  ", true)
      ("this", false)
      (" ", true)
      ("is", false)
      (" ", true)
      ("an", false)
      ("  ", true)
      ("example", false)
      ("  ", true)

  Source Edit

# Exports

toLower, toLower, toLower, toUpper, toUpper, toUpper