Skip to content

strings Module

The strings module provides functions for string manipulation.

String Builder

Harneet provides a strings.Builder for efficient string concatenation, modeled after Go's strings.Builder.

Creating a Builder

Use the constructor to create a builder instance:

Creating a Builder
1
2
3
4
package main
import strings

var b, err = strings.NewBuilder()

Returns (builder, error) where error is None on success.

Methods

  • WriteString(s string) (int, error) Appends s to the builder and returns bytes written.

  • String() (string, error) Returns the accumulated string.

Example

Builder Example
package main
import fmt
import strings

var b, err = strings.NewBuilder()
if err != None {
    fmt.Println("Error:", err)
} else {
    var _, e1 = b.WriteString("Hello")
    var _, e2 = b.WriteString(" ")
    var _, e3 = b.WriteString("World")
    if e1 == None and e2 == None and e3 == None {
        var out, e4 = b.String()
        if e4 == None {
            fmt.Println(out) // Hello World
        }
    }
}

Notes

  • Follow normal tuple-return patterns: always check the error value.
  • strings.Builder is ideal for building large strings incrementally.

Multiline Strings

Harneet supports multiline strings using backtick (`) delimiters. These are raw strings that preserve formatting and don't interpret escape sequences, making them perfect for SQL queries, HTML templates, JSON data, and configuration files.

Basic Syntax

Multiline String Syntax
1
2
3
var multilineString = `This is a multiline string
that spans multiple lines
and preserves all formatting`

Key Features

  • Raw String Behavior: No escape sequence processing - backslashes, quotes, and other special characters are treated literally
  • Formatting Preservation: All whitespace, indentation, and line breaks are preserved exactly as written
  • No Escaping Required: Include quotes, backslashes, and other special characters without escaping

Common Use Cases

SQL Queries

SQL Queries
var createTableSQL = `
    CREATE TABLE users (
        id INTEGER PRIMARY KEY,
        username VARCHAR(50) NOT NULL,
        email VARCHAR(100) NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    )
`

var complexQuery = `
    SELECT u.username, p.title, COUNT(c.id) as comment_count
    FROM users u
    LEFT JOIN posts p ON u.id = p.author_id
    LEFT JOIN comments c ON p.id = c.post_id
    WHERE u.is_active = TRUE
    GROUP BY u.id, p.id
    ORDER BY comment_count DESC
`

JSON Data

JSON Data
var userJSON = `{
    "id": 12345,
    "name": "John Doe",
    "email": "john@example.com",
    "preferences": {
        "theme": "dark",
        "notifications": true
    },
    "tags": ["developer", "premium"]
}`

HTML Templates

HTML Templates
var htmlTemplate = `<!DOCTYPE html>
<html>
<head>
    <title>Welcome</title>
    <style>
        .container { margin: 20px; }
        .header { color: #333; }
    </style>
</head>
<body>
    <div class="container">
        <h1 class="header">Hello, World!</h1>
        <p>This is a "quoted" string with 'mixed' quotes.</p>
    </div>
</body>
</html>`

Configuration Files

Configuration Files
var configYAML = `
server:
  host: "0.0.0.0"
  port: 8080
  ssl:
    enabled: true
    cert_path: "/etc/ssl/certs/app.crt"
    key_path: "/etc/ssl/private/app.key"

database:
  host: "localhost"
  port: 5432
  name: "myapp"
  user: "dbuser"
`

Raw String Examples

Multiline strings are raw strings, meaning special characters are treated literally:

Raw String Examples
// File paths with backslashes (no escaping needed)
var windowsPath = `C:\Users\John\Documents\file.txt`

// Regular expressions with backslashes
var regexPattern = `\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}`

// Mixed quotes without escaping
var mixedQuotes = `He said "Hello" and she replied 'Hi there!'`

// Literal backslash sequences
var literalEscapes = `These are literal: \n \t \r \" \'`

Integration with String Functions

Multiline strings work seamlessly with all existing string functions:

Integration with String Functions
package main
import fmt
import strings

var multilineText = `Line 1
Line 2
Line 3`

// Get length
var length, _ = strings.Len(multilineText)
fmt.Printf("Length: %d\n", length)

// Convert to uppercase
var upper, _ = strings.Upper(multilineText)
fmt.Println("Uppercase:", upper)

// Split by newlines
var lines, _ = strings.Split(multilineText, "\n")
fmt.Println("Lines:", lines)

// Check if contains text
var hasLine2, _ = strings.Contains(multilineText, "Line 2")
fmt.Printf("Contains 'Line 2': %t\n", hasLine2)

Best Practices

  1. Use for Formatted Content: Perfect for SQL, HTML, JSON, YAML, and other structured text
  2. Preserve Indentation: Maintain consistent indentation for readability
  3. No Escape Sequences: Remember that \n, \t, etc. are literal characters, not escape sequences
  4. String Operations: All existing string functions work normally with multiline strings

Migration from Regular Strings

If you have existing code with escaped strings, you can easily migrate to multiline strings:

Migration Example
1
2
3
4
5
6
7
// Before (with escaping)
var oldSQL = "SELECT *\nFROM users\nWHERE id = 1"

// After (multiline string)
var newSQL = `SELECT *
FROM users
WHERE id = 1`

Common Gotchas and Best Practices

Gotcha 1: Literal vs Interpreted Escape Sequences

Escape Sequences Gotcha
1
2
3
4
5
6
7
8
9
// Regular string - \n creates actual newline
var regular = "Line 1\nLine 2"

// Multiline string - \n is literal text
var multiline = `Line 1\nLine 2`

// For actual newlines in multiline strings, use line breaks
var actualNewlines = `Line 1
Line 2`

Gotcha 2: Leading and Trailing Whitespace

Whitespace Gotcha
// This includes leading and trailing newlines
var withWhitespace = `
    Content here
`

// This doesn't include extra newlines
var cleanContent = `Content here`

// This preserves indentation but no extra newlines
var indentedClean = `    Content here
    More content`

Gotcha 3: Backticks in Content

Backticks Gotcha
1
2
3
4
5
// If you need literal backticks, use regular strings
var codeExample = "Use `backticks` for multiline strings in Harneet"

// Or in documentation contexts
var docExample = "Multiline strings use `` ` `` delimiters"

Best Practice 1: Consistent Indentation

Consistent Indentation
// ✅ Good: Consistent indentation for readability
var wellFormatted = `
    SELECT u.name, u.email
    FROM users u
    WHERE u.active = TRUE
    ORDER BY u.created_at DESC
`

// ❌ Avoid: Inconsistent indentation
var poorlyFormatted = `
SELECT u.name, u.email
    FROM users u
WHERE u.active = TRUE
        ORDER BY u.created_at DESC
`

Best Practice 2: Choose the Right String Type

Choosing String Type
// ✅ Use regular strings for simple text
var simpleMessage = "Hello, World!"

// ✅ Use multiline strings for formatted content
var formattedContent = `{
    "message": "Hello, World!",
    "timestamp": "2024-01-20T10:30:00Z"
}`

// ✅ Use regular strings when you need escape sequences
var withNewlines = "First line\nSecond line\nThird line"

// ✅ Use multiline strings when you want literal backslashes
var filePath = `C:\Users\John\Documents\file.txt`

Best Practice 3: String Operations Work Identically

String Operations
import strings

var multilineData = `{
    "users": [
        {"name": "Alice", "age": 30},
        {"name": "Bob", "age": 25}
    ]
}`

// All string functions work normally
var length, _ = strings.Len(multilineData)
var hasUsers, _ = strings.Contains(multilineData, "users")
var upperData, _ = strings.Upper(multilineData)

// Split by actual newlines (not \n characters)
var lines, _ = strings.Split(multilineData, "\n")

Slicing strings

Strings in Harneet support Go-like slicing using the s[a:b] syntax (and the shorthand forms [:b], [a:], and [:]).

Rules and semantics: - Indices a and b must be integers. The type checker validates this. - Bounds are clamped to the valid range [0, len(s)]. - Half-open interval: a is inclusive, b is exclusive. - If a > b, the result is an empty string. - Slicing is currently byte-based. If your strings contain multi-byte UTF-8 characters, make sure your indices align with character boundaries to avoid splitting a rune. Rune-aware slicing may be added in the future.

Examples:

String Slicing
1
2
3
4
5
6
7
package main
import fmt

var s = "abcdef"
fmt.Println(s[0:3]) // "abc"
fmt.Println(s[2:])  // "cdef"
fmt.Println(s[:])   // "abcdef"

See array and typed-array slicing semantics: arrays module documentation.

Functions

Len(string)

Returns the length of a string.

Parameters: - string: A string.

Returns: - (integer, error): The length of the string, or an error if the argument is not a string.

Example:

Len Example
package main
import fmt
import strings

var length, err = strings.Len("hello")
if err != None {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Length:", length) // Output: Length: 5
}


FromCodePoint(int)

Constructs a single-character string from a Unicode code point (rune).

Parameters: - int: Unicode code point in the range 0..0x10FFFF.

Returns: - (string, error): The single-character string, or an error if the code point is out of range.

Example:

FromCodePoint Example
1
2
3
4
5
6
7
8
package main
import fmt
import strings

var s, err = strings.FromCodePoint(0x1F600)
if err == None {
    fmt.Println(s) // 😀
}

CodePoints(string)

Converts a UTF-8 string into an array of Unicode code points (runes) represented as integers.

Parameters: - string: Input string.

Returns: - (array, error): An array of integers, one per Unicode code point in the string, or an error if the argument is not a string.

Example:

CodePoints Example
package main
import fmt
import strings

var s string = "go"

// Get code points [103, 111]
var cps, err = strings.CodePoints(s)
if err != None {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Code points:", cps)
}

// Iterate like Go's `for i, r := range "go"`
for i, cp in cps {
    fmt.Println(i, cp)
}


Upper(string)

Converts a string to uppercase.

Parameters: - string: A string.

Returns: - (string, error): The uppercase version of the string, or an error if the argument is not a string.

Example:

Upper Example
1
2
3
4
5
6
7
8
9
import fmt
import strings

var upper, err = strings.Upper("hello")
if err != None {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Uppercase:", upper) // Output: Uppercase: HELLO
}


Lower(string)

Converts a string to lowercase.

Parameters: - string: A string.

Returns: - (string, error): The lowercase version of the string, or an error if the argument is not a string.

Example:

Lower Example
1
2
3
4
5
6
7
8
9
import fmt
import strings

var lower, err = strings.Lower("HELLO")
if err != None {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Lowercase:", lower) // Output: Lowercase: hello
}


Contains(string, substring)

Checks if a string contains a substring.

Parameters: - string: The string to search in. - substring: The substring to search for.

Returns: - (boolean, error): true if the substring is found, false otherwise. Returns an error if the arguments are not strings.

Example:

Contains Example
1
2
3
4
5
6
7
8
9
import fmt
import strings

var found, err = strings.Contains("hello world", "world")
if err != None {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Found:", found) // Output: Found: true
}


Replace(string, old, new)

Replaces all occurrences of a substring with a new string.

Parameters: - string: The original string. - old: The substring to be replaced. - new: The new string to replace with.

Returns: - (string, error): A new string with all occurrences of old replaced by new. Returns an error if the arguments are not strings.

Example:

Replace Example
1
2
3
4
5
6
7
8
9
import fmt
import strings

var replaced, err = strings.Replace("hello world", "world", "Harneet")
if err != None {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Replaced:", replaced) // Output: Replaced: hello Harneet
}


Split(string, separator)

Splits a string into an array of substrings.

Parameters: - string: The string to be split. - separator: The separator to split by.

Returns: - (array, error): An array of strings. Returns an error if the arguments are not strings.

Example:

Split Example
1
2
3
4
5
6
7
8
9
import fmt
import strings

var parts, err = strings.Split("a,b,c", ",")
if err != None {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Parts:", parts) // Output: Parts: [a, b, c]
}


ToInt(string)

Parses a string to an integer.

Parameters: - string: The string to be parsed.

Returns: - (integer, error): The integer value, or an error if the string cannot be parsed as an integer.

Example:

ToInt Example
import fmt
import strings

var number, err = strings.ToInt("42")
if err != None {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Number:", number) // Output: Number: 42
}

var invalid, err2 = strings.ToInt("hello")
if err2 != None {
    fmt.Println("Error:", err2) // Output: Error: cannot convert 'hello' to int
}


HasPrefix(string, prefix)

Checks whether a string begins with the given prefix.

Parameters: - string: The string to test. - prefix: The prefix to check.

Returns: - (boolean, error): true if string starts with prefix, else false.

Example:

HasPrefix Example
1
2
3
4
5
import fmt
import strings

var ok, err = strings.HasPrefix("foobar", "foo")
fmt.Println(ok) // true


HasSuffix(string, suffix)

Checks whether a string ends with the given suffix.

Parameters: - string: The string to test. - suffix: The suffix to check.

Returns: - (boolean, error): true if string ends with suffix, else false.

Example:

HasSuffix Example
1
2
3
4
5
import fmt
import strings

var ok, err = strings.HasSuffix("foobar", "bar")
fmt.Println(ok) // true


Index(string, substr)

Returns the index of the first occurrence of substr in string, or -1 if not present.

Parameters: - string: The string to search. - substr: The substring to find.

Returns: - (integer, error): The index or -1.

Example:

Index Example
1
2
3
4
5
import fmt
import strings

var i, err = strings.Index("hello", "l")
fmt.Println(i) // 2


LastIndex(string, substr)

Returns the index of the last occurrence of substr in string, or -1 if not present.

Parameters: - string: The string to search. - substr: The substring to find.

Returns: - (integer, error): The index or -1.

Example:

LastIndex Example
1
2
3
4
5
import fmt
import strings

var i, err = strings.LastIndex("hello", "l")
fmt.Println(i) // 3


Trim(string, cutset)

Removes all leading and trailing characters in cutset from string.

Parameters: - string: The string to trim. - cutset: Characters to trim from both ends.

Returns: - (string, error): The trimmed string.

Example:

Trim Example
1
2
3
4
5
import fmt
import strings

var out, err = strings.Trim("--hello--", "-")
fmt.Println(out) // hello


TrimSpace(string)

Removes leading and trailing Unicode whitespace.

Parameters: - string: The string to trim.

Returns: - (string, error): The trimmed string.

Example:

TrimSpace Example
1
2
3
4
5
import fmt
import strings

var out, err = strings.TrimSpace("  spaced  ")
fmt.Println(out) // spaced


TrimPrefix(string, prefix)

Removes prefix from the start of string if present.

Parameters: - string: The input string. - prefix: Prefix to remove.

Returns: - (string, error): The result string.

Example:

TrimPrefix Example
1
2
3
4
5
import fmt
import strings

var out, err = strings.TrimPrefix("prefix_value", "prefix_")
fmt.Println(out) // value


TrimSuffix(string, suffix)

Removes suffix from the end of string if present.

Parameters: - string: The input string. - suffix: Suffix to remove.

Returns: - (string, error): The result string.

Example:

TrimSuffix Example
1
2
3
4
5
import fmt
import strings

var out, err = strings.TrimSuffix("value_suffix", "_suffix")
fmt.Println(out) // value


Repeat(string, count)

Returns a new string consisting of count copies of string.

Parameters: - string: The string to repeat. - count: Number of repetitions (non-negative).

Returns: - (string, error): The repeated string.

Example:

Repeat Example
1
2
3
4
5
import fmt
import strings

var out, err = strings.Repeat("ha", 3)
fmt.Println(out) // hahaha


Count(string, substr)

Counts non-overlapping instances of substr in string.

Parameters: - string: The string to search. - substr: The substring to count.

Returns: - (integer, error): The count.

Example:

Count Example
1
2
3
4
5
import fmt
import strings

var c, err = strings.Count("banana", "na")
fmt.Println(c) // 2


Join(array, sep)

Joins an array of strings using the separator sep.

Parameters: - array: Array of strings. - sep: Separator string.

Returns: - (string, error): The joined string.

Example:

Join Example
1
2
3
4
5
6
import fmt
import strings

var parts = ["go", "is", "fun"]
var out, err = strings.Join(parts, " ")
fmt.Println(out) // go is fun


Fields(string)

Splits a string around runs of Unicode whitespace.

Parameters: - string: Input string.

Returns: - (array, error): Array of fields.

Example:

Fields Example
1
2
3
4
5
import fmt
import strings

var arr, err = strings.Fields(" a  b\t c\n")
fmt.Println(arr) // [a, b, c]


ReplaceN(string, old, new, n)

Replaces up to n non-overlapping instances of old with new. If n < 0, replaces all.

Parameters: - string: Source string. - old: Substring to replace. - new: Replacement string. - n: Maximum number of replacements (-1 for all).

Returns: - (string, error): The result string.

Example:

ReplaceN Example
1
2
3
4
5
6
7
8
import fmt
import strings

var out1, err1 = strings.ReplaceN("aaaa", "a", "b", 2)
fmt.Println(out1) // bbaa

var out2, err2 = strings.ReplaceN("aaaa", "a", "b", -1)
fmt.Println(out2) // bbbb


EqualFold(a, b)

Reports whether a and b are equal under simple Unicode case-folding.

Parameters: - a: First string. - b: Second string.

Returns: - (boolean, error): true if equal ignoring case.

Example:

EqualFold Example
1
2
3
4
5
import fmt
import strings

var ok, err = strings.EqualFold("GoLang", "golang")
fmt.Println(ok) // true


Compare(a, b)

Lexicographically compares two strings.

Parameters: - a: First string. - b: Second string.

Returns: - (integer, error): 0 if equal, -1 if a < b, +1 if a > b.

Example:

Compare Example
1
2
3
4
5
6
7
8
import fmt
import strings

var c1, err1 = strings.Compare("abc", "abd")
fmt.Println(c1) // -1

var c2, err2 = strings.Compare("same", "same")
fmt.Println(c2) // 0