ESC
Type to search...
S
Soli Docs

Strings

UTF-8 text with powerful built-in methods for manipulation, searching, and transformation.

Creating Strings

String Literals

Create strings using double quotes. Supports escape sequences for special characters.

# Basic string literals
let greeting = "Hello, World!"
let name = "Alice"
let empty = ""

# Escape sequences
let newline = "Line 1\nLine 2"
let tab = "Column1\tColumn2"
let quote = "She said \"Hello\""
let backslash = "Path: C:\\Users\\name"

# Unicode characters
let emoji = "Hello \u{1F44B}";  # Hello with wave emoji
let unicode = "\u{00E9}";       # e with accent
Raw Strings

Raw strings don't process escape sequences - useful for paths and regex patterns.

# Raw strings - no escape processing
let path = r"C:\Users\name\Documents"
let regex = r"\d+\.\d+"

# Compare with regular strings
let regular = "C:\\Users\\name";  # Need double backslashes
let raw = r"C:\Users\name";       # Single backslashes work
Multiline Strings

Use triple quotes or bracket syntax for multiline strings. Preserves newlines and indentation.

# Triple quote syntax (recommended)
let poem = """The fog comes
on little cat feet.
It sits looking
over harbor and city."""

# Bracket syntax [[ ]]
let story = [[Once upon
a time in
the wild west.]]

# HTML template example
let html = """

Welcome

This is a paragraph.

""" # SQL query example let query = """SELECT id, name, email FROM users WHERE active = true ORDER BY created_at DESC""";

Note: Both syntaxes create raw strings (no escape processing). The leading newline and indentation are preserved as-is. Use .trim to remove leading/trailing whitespace if needed.

Concatenation

Join strings together using the + operator. Non-string values are automatically converted.

# Basic concatenation
let greeting = "Hello, " + "World!";  # "Hello, World!"

# Auto-conversion of other types
let message = "Value: " + 42;         # "Value: 42"
let result = "Pi is " + 3.14159;      # "Pi is 3.14159"
let status = "Active: " + true;       # "Active: true"

# Building strings
let name = "Alice"
let age = 30
let intro = "My name is " + name + " and I am " + age.to_s + " years old."
String Interpolation

Embed expressions directly in strings using #{expression} syntax.

# Basic variable interpolation
let name = "World"
let greeting = "Hello #{name}!";           # "Hello World!"

# Arithmetic expressions
let a = 2
let b = 3
let result = "Sum is #{a + b}";             # "Sum is 5"

# Multiple interpolations
let first = "John"
let last = "Doe"
let full = "#{first} #{last}";              # "John Doe"

# Method calls
let text = "hello"
let upper = "Upper: #{text.upper()}";        # "Upper: HELLO"

# Array access
let items = ["Alice", "Bob"]
let first_item = "First: #{items[0]}";       # "First: Alice"

# Hash access
let person = {"name": "Charlie"}
let person_name = "Name: #{person["name"]}"; # "Name: Charlie"
Type Annotations

Optionally specify string types for clarity and type safety.

# Typed strings
let name: String = "Alice"
let message: String = ""

# String arrays
let names: String[] = ["Alice", "Bob", "Charlie"]

# Function parameters
def greet(name: String) -> String
    "Hello, " + name + "!"
end

Accessing Characters

Index Access

Access individual characters using zero-based indexing. Negative indices count from the end.

let str = "Hello, World!"

# Zero-based indexing
print(str[0]);    # "H" (first character)
print(str[7]);    # "W"

# Negative indexing
print(str[-1]);   # "!" (last character)
print(str[-2]);   # "d" (second to last)

# Out of bounds returns null
print(str[100]);  # null
String Immutability

Strings are immutable - methods return new strings rather than modifying the original.

let original = "hello"
let upper = original.upcase
print(original)  # "hello" (unchanged)
print(upper)     # "HELLO" (new string)

# To "modify", reassign the variable
let text = "hello"
text = text.upcase
print(text)  # "HELLO"

String Methods

All string methods are called with dot notation on string values.

.length / .len / .size

Returns the number of characters in the string.

"hello".length  # 5
"hello".size    # 5
"".len          # 0
.bytesize / .bytes

bytesize returns the number of bytes (UTF-8). bytes returns the byte values as an array.

"hello".bytesize  # 5
"hello".bytes     # [104, 101, 108, 108, 111]
.empty? / .blank? / .present?

Check if string is empty, blank (empty or only whitespace), or present (not blank).

"".empty?       # true
"hello".empty?  # false
"   ".empty?    # false

"".blank?       # true
"   ".blank?    # true (only whitespace)
"hello".blank?  # false

"hello".present?  # true
"".present?       # false
"   ".present?    # false
.inspect / .class / .is_a?(type) / .nil?

Introspection methods for debugging and type checking.

"hello".inspect           # "\"hello\""
"hello".class             # "String"
"hello".is_a?("String")  # true
"hello".nil?              # false
.upcase / .downcase / .capitalize / .swapcase

Case conversion methods. uppercase and lowercase are aliases for upcase and downcase.

"hello".upcase       # "HELLO"
"HELLO".downcase     # "hello"
"hello".capitalize   # "Hello"
"Hello World".swapcase  # "hELLO wORLD"

# Aliases
"hello".uppercase    # "HELLO"
"HELLO".lowercase    # "hello"
.contains(substr) / .includes?(substr)

Checks if the string contains a substring. includes? is an alias.

"hello world".contains("world")  # true
"hello world".contains("foo")    # false
"hello".includes?("ell")         # true
.starts_with(prefix) / .ends_with(suffix)

Check if a string starts or ends with a given substring. Also available as starts_with? and ends_with?.

"https://example.com".starts_with("https://")  # true
"report.pdf".ends_with(".pdf")                  # true

# With ? suffix (alias)
"hello".starts_with?("he")  # true
"hello".ends_with?("lo")    # true
.index_of(substr)

Returns the index of the first occurrence of a substring, or -1 if not found.

"hello world".index_of("world")  # 6
"hello world".index_of("o")      # 4
"hello world".index_of("foo")    # -1
.count(substr)

Counts the number of occurrences of a substring.

"hello".count("l")       # 2
"banana".count("ana")    # 1
"hello".count("x")       # 0
.match(pattern) / .scan(pattern)

match returns the first regex match. scan returns all matches as an array.

"hello 42 world 7".match(r"\d+")   # "42"
"hello 42 world 7".scan(r"\d+")    # ["42", "7"]
.trim / .strip / .lstrip / .rstrip / .chomp

Whitespace removal. trim (alias strip) removes both sides, lstrip/rstrip remove left/right only, chomp removes trailing newlines.

"  hello  ".trim     # "hello"
"  hello  ".strip    # "hello"  (alias)
"  hello  ".lstrip   # "hello  "
"  hello  ".rstrip   # "  hello"
"hello\n".chomp      # "hello"
.squeeze

Collapses runs of repeated characters into a single character.

"aaabbbccc".squeeze     # "abc"
"hello    world".squeeze  # "helo world"
.reverse

Returns a new string with characters in reverse order.

"hello".reverse   # "olleh"
"12345".reverse   # "54321"
.replace(search, replacement) / .gsub(pattern, replacement) / .sub(pattern, replacement)

replace replaces all occurrences. gsub replaces all regex matches. sub replaces first regex match only.

"hello world".replace("world", "Soli")  # "hello Soli"
"aaa".replace("a", "b")                 # "bbb"

"hello 42 world 7".gsub(r"\d+", "X")   # "hello X world X"
"hello 42 world 7".sub(r"\d+", "X")    # "hello X world 7"
.tr(from, to)

Translates characters: replaces each character in from with the corresponding character in to.

"hello".tr("aeiou", "*")      # "h*ll*"
"hello".tr("el", "ip")        # "hippo"
.delete(chars) / .delete_prefix(prefix) / .delete_suffix(suffix)

delete removes all occurrences of specified characters. delete_prefix/delete_suffix remove a specific prefix or suffix.

"hello".delete("lo")                    # "he"
"Hello, World!".delete_prefix("Hello, ")  # "World!"
"report.pdf".delete_suffix(".pdf")       # "report"
.insert(index, string)

Inserts a string at the specified index position.

"helo".insert(3, "l")    # "hello"
"world".insert(0, "hello ")  # "hello world"
.truncate(length)

Truncates the string to the specified length.

"hello world".truncate(5)  # "hello"
"hi".truncate(10)          # "hi"
.substring(start, end?)

Extracts a portion of the string from start index to end index (exclusive).

"hello".substring(0, 2)   # "he"
"hello".substring(2)      # "llo"
"hello".substring(-3)     # "llo"
.split(separator) / .join(separator)

split splits a string into an array. join joins characters back with a separator.

"a,b,c".split(",")        # ["a", "b", "c"]
"hello world".split(" ")  # ["hello", "world"]
"hello".split("")         # ["h", "e", "l", "l", "o"]
.chars / .lines

chars splits into individual characters. lines splits by newlines.

"hello".chars                    # ["h", "e", "l", "l", "o"]
"line1\nline2\nline3".lines      # ["line1", "line2", "line3"]

for (c in "Soli".chars)
    print(c)
end
.partition(separator) / .rpartition(separator)

Splits into 3 parts: [before, separator, after]. rpartition searches from the right.

"hello-world-test".partition("-")   # ["hello", "-", "world-test"]
"hello-world-test".rpartition("-")  # ["hello-world", "-", "test"]
.lpad(width, char?) / .rpad(width, char?) / .center(width, char?)

Pad a string to a specified width. ljust/rjust are aliases for rpad/lpad.

"42".lpad(5, "0")      # "00042"
"hi".rpad(5, ".")      # "hi..."
"hi".center(7, "-")    # "--hi---"

# Default pad char is space
"5".lpad(3)            # "  5"
"hi".rpad(5)           # "hi   "
.ord / .chr / .hex / .oct

Character encoding conversions. ord returns the Unicode code point, chr returns the character, hex/oct convert to hexadecimal/octal representation.

"A".ord    # 65
"A".hex    # "41"
"A".oct    # "101"
.to_i / .to_f / .to_s / .to_string / .to_sym / .parse_json

Type conversion methods. to_int/to_float are aliases for to_i/to_f.

"42".to_i        # 42
"3.14".to_f      # 3.14
42.to_s          # "42"
[1,2,3].to_string  # "[1, 2, 3]"

# Convert to symbol
"name".to_sym    # :name
"hello".to_sym   # :hello

# Parse JSON
'{"name":"Alice"}'.parse_json  # {"name": "Alice"}
"[1,2,3]".parse_json           # [1, 2, 3]
"not json".parse_json          # {}

HTML Functions

html_escape(string)

Escape HTML special characters to prevent XSS attacks.

html_escape("<div class='test'>Hello</div>")
# "&lt;div class='test'&gt;Hello&lt;/div&gt;"

html_escape("Tom & Jerry")
# "Tom &amp; Jerry"

html_escape("5 > 3 && 3 < 5")
# "5 &gt; 3 &amp;&amp; 3 &lt; 5"
html_unescape(string)

Convert HTML entities back to their original characters.

html_unescape("&lt;div&gt;")
# "<div>"

html_unescape("Tom &amp; Jerry")
# "Tom & Jerry"
sanitize_html(string)

Remove dangerous HTML tags while keeping safe formatting tags.

sanitize_html("<b>Bold</b> <style>body{color:red}</style>")
# "<b>Bold</b> "

sanitize_html("<p>Hello</p><object data='file.swf'></object>")
# "<p>Hello</p>"

Common Patterns

Parsing and Formatting
# Parse CSV line
let csv_line = "Alice,30,Engineer"
let fields = csv_line.split(",")
let name = fields[0]      # "Alice"
let age = fields[1].to_i  # 30
let job = fields[2]       # "Engineer"

# Parse URL query string
def parse_query(query: String) -> Hash
    let result = {}
    let pairs = query.split("&")
    for (pair in pairs)
        let parts = pair.split("=")
        if (parts.length == 2)
            result[parts[0]] = parts[1]
        end
    end
    result
end
let params = parse_query("name=Alice&age=30")
# {"name": "Alice", "age": "30"}
Validation Helpers
# Basic email validation
def is_valid_email(email: String) -> Bool
    email.contains("@") && email.contains(".")
end

# Check minimum length
def has_min_length(s: String, min: Int) -> Bool
    s.length >= min
end

# Check if string is numeric
def is_numeric(s: String) -> Bool
    if (s.empty?)
        return false
    end
    for (c in s.chars)
        if (!"0123456789".contains(c))
            return false
        end
    end
    true
end

# Validate username
def is_valid_username(username: String) -> Bool
    let trimmed = username.trim
    trimmed.length >= 3 && trimmed.length <= 20
end
Template Strings
# Simple template replacement
def template(text: String, vars: Hash) -> String
    let result = text
    for (pair in entries(vars))
        let key = pair[0]
        let value = pair[1]
        result = result.replace("{{" + key + "}}", value.to_string)
    end
    result
end

let tmpl = "Hello, {{name}}! You have {{count}} messages."
let output = template(tmpl, {"name": "Alice", "count": 5})
# "Hello, Alice! You have 5 messages."

# Build HTML safely
def build_link(url: String, text: String) -> String
    "" + html_escape(text) + ""
end