# Strings (https://docs-fpm2731fy-ton-core-docs.vercel.app/llms/tolk/types/strings/content.md)



Tolk provides a dedicated `string` type. At the TVM level, a string is a [cell](/llms/languages/tolk/types/cells/content.md) that stores data in snake format: a chain of cells where each cell holds a portion of the string and a reference to the next.

## String literals [#string-literals]

Every string literal produces a value of type `string`:

```tolk
// string
val str = "hello";

// array<string>
val arr = ["one", "two"];
```

However, on the TVM, each literal is a cell:

```tolk
// a cell with 40 bits of data
val str = "hello";
```

A literal cell is created at compile-time, there is no expensive 500-gas cell creation at runtime.

## Snake format [#snake-format]

Since a single cell can hold at most 1023 bits (127 bytes), longer strings use the snake format: the start of the string is placed in the root cell, with its continuation in a referenced cell, recursively:

```tolk
val str = "very1 very2 ... very99 long";
// stored approximately as:
// "very1 ... very30"
//   -> ref "very31 ... very60"
//     -> ref "very61 ... very89"
//       -> ref "very90 ... very99 long"
```

Short strings may also be stored in snake format — for example, after concatenation. The logical value `"abcd"` and the snaked `"ab" -> ref "cd"` are treated identically.

<Callout type="caution">
  Because the same logical string can have different low-level representations, comparing strings via cell hashes is incorrect. Use the [`string.hash` method](#string-hash) instead.
</Callout>

## Traversing [#traversing]

To manually traverse contents of a string, call a `beginParse()` method that returns `slice`:

```tolk
val bin = str.beginParse();  // slice
bin.remainingBitsCount();    // 40
```

<Callout type="caution">
  Be careful traversing the string manually. Strings are stored in snake format, so longer strings span multiple cells linked by references.
</Callout>

## String methods [#string-methods]

Standard library methods for strings require an explicit import:

```tolk
import "@stdlib/strings"
```

### `string.calculateLength` [#stringcalculatelength]

Loops over all references and returns the total number of characters:

```tolk
val len = someStr.calculateLength();
```

Both `"abcd"` and `"a" -> ref "bc" -> ref "d"` return 4.

### `string.equalTo` [#stringequalto]

Compares two strings for equality, accounting for their snaked internals:

```tolk
if (option.equalTo("--disable")) {
    // ...
}
```

For instance, `"--disable"` equals `"--dis" -> ref "able"`.

### `string.hash` [#stringhash]

Returns a hash of the string regardless of its internal representation. The hash of `"abcd"` and `"a" -> ref "bcd"` is identical.

### Compile-time methods [#compile-time-methods]

Several methods operate on [string literals](#string-literals) at compile-time. Such strings are evaluated during compilation and embedded into the contract as constants.

```tolk
// calculates crc32 of a string
const crc32 = "some_str".crc32() // = 4013618352 = 0xEF3AF4B0

// calculates crc16 (XMODEM) of a string
const crc16 = "some_str".crc16() // = 53407 = 0xD09F

// calculates sha256 of a string and returns 256-bit integer
const hash = "some_crypto_key".sha256()

// calculates sha256 of a string and takes the first 32 bits
const minihash = "some_crypto_key".sha256_32()

// interprets an N-chars ascii string as a number in base 256
const base256 = "AB".toBase256() // = 16706 (65*256 + 66)

// a slice with 2 bytes: 16, 32 (constructed from hex)
const hexSlice = "1020".hexToSlice()

// a slice with 4 bytes: 97, 98, 99, 100
const rawSlice = "abcd".literalSlice()
```

These methods work only on constant strings: calling them on variables produces a compilation error.

## `StringBuilder` [#stringbuilder]

`StringBuilder` from `@stdlib/strings` concatenates several strings into one snake-encoded string:

```tolk
import "@stdlib/strings"

fun build() {
    var sb = StringBuilder.create();
    sb.append("ab");
    sb.append("cd");
    // "abcd", stored as "ab" -> ref "cd"
    var str = sb.build();
}
```

### `StringBuilder.append` [#stringbuilderappend]

The method `StringBuilder.append` returns `self` and can be chained:

```tolk
var str = StringBuilder.create()
         .append("ab")
         .append("cd")
         .build();
```

A practical example: an NFT collection with common content and per-item content:

```tolk
get fun get_nft_content(itemIndex: int, individualLink: string) {
    // ...
    var link = StringBuilder.create()
              .append(commonContent)
              .append(individualLink)
              .build();
    // ...
}
```

The method `StringBuilder.append` always concatenates strings in the snake format. This does not affect the final representation, since both `"abcd"` and `"ab" -> ref "cd"` are the same logical string.

### `StringBuilder.appendInt` [#stringbuilderappendint]

Stores an integer in decimal format. This method is gas-expensive. It is suitable for contract getters executed off-chain, but should be avoided in on-chain production environments:

```tolk
var link = StringBuilder.create()
           .append("/images/")
           .appendInt(itemIndex)
           .append(".png")
           .build();
```

## TEP-compliant encoding [#tep-compliant-encoding]

Per the [token metadata standard](/llms/standard/tokens/metadata/content.md), strings returned from get-methods must contain prefixes for off-chain explorers and APIs:

* `0x00` + `"<STRING>"` — a regular snake-encoded string
* `0x01` + `"<STRING>"` — an off-chain content URL

Prefixing does not create a new entity — the result remains a `string`, a concatenation of one character and the original content.

Standard library contains an alias: `type string_prefixed0x = string`. Use this alias to indicate that a string is intentionally prefixed. Because it is an alias, the value remains a string (a TVM cell) at runtime and stays opaque to clients.

Use specialized methods `string.prefixWith00` and `string.prefixWith01` for prefixing metadata strings:

<CodeGroup>
  <CodeBlockTabs defaultValue="NFT example">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="NFT example">
        NFT example
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Jetton example">
        Jetton example
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="NFT example">
      ```tolk  wrap lines
      get fun get_nft_content(itemIndex: int, individualLink: string): string_prefixed0x {
          // ...
          return StringBuilder.create()
              .append(content.commonContent)
              .append(individualLink)
              .build()
              // to comply with TEPs off-chain content layout
              .prefixWith01()
      }
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Jetton example">
      ```tolk  wrap lines
      metadata.contentDict.set("uri".sha256(), storage.metadataUri.prefixWith00());
      metadata.contentDict.set("decimals".sha256(), "9".prefixWith00());
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Stack layout and serialization [#stack-layout-and-serialization]

A string is backed by the snake-encoded TVM `CELL`. Serialized as a single cell reference.
