---
title: "String operations"
description: "Server-side string read, modify, and type-conversion operations for String bins with full UTF-8 support."
---

# String operations

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

Server-side read, modify, and type-conversion operations for String bins, invoked through the [`operate`](https://aerospike.com/docs/develop/learn/bin-operations) API to search, transform, extract, and normalize text without fetch-modify-write round-trips. For conceptual guidance, UTF-8 validation, and worked examples, see the [String operations overview](https://aerospike.com/docs/develop/data-types/string).

Every operation on this page also has an expression form, which evaluates to a value instead of writing it. See [String expressions](https://aerospike.com/docs/develop/expressions/string) for those, and [Operations and expressions](https://aerospike.com/docs/develop/learn/operations-and-expressions/) for which to reach for.

String operations require Aerospike Database 8.2.0 or later. Earlier versions do not recognize the opcodes and reject the command. Each operation lists the version it was introduced in.

## Unicode semantics

String operations treat bin values as UTF-8 text:

-   [`strlen`](#strlen) counts Unicode codepoints; [`byte_length`](#byte_length) counts UTF-8 bytes.
-   [`substr`](#substr), [`char_at`](#char_at), [`insert`](#insert), and [`snip`](#snip) take codepoint indexes. Negative indexes count from the end of the string, and out-of-range indexes are clamped to `[0, length]`.
-   Substring matching in [`find`](#find), [`contains`](#contains), [`starts_with`](#starts_with), [`ends_with`](#ends_with), [`replace`](#replace), and [`replace_all`](#replace_all) treats canonically equivalent text as equal, so precomposed `é` (U+00E9) matches `e` followed by combining acute (U+0301).
-   Expression comparison operators (`eq`, `ne`, `gt`, `ge`, `lt`, `le`) compare String values by UTF-8 bytes and do not treat those spellings as equal. See [Compare String values](https://aerospike.com/docs/develop/data-types/string/comparison).

When both the bin value and all arguments are ASCII, the server operates directly on bytes instead of converting to UTF-16 for processing. No client configuration is required.

## Context

Every operation except [`to_string`](#to_string) takes an optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) selecting a String nested inside a List or Map bin. Omit it to target the bin value itself.

A modify operation against a missing bin is not an error: `insert`, `concat`, `append`, `prepend`, `overwrite`, `repeat`, `pad_start`, and `pad_end` create it, and every other modify operation leaves the record unchanged and returns success.

A bin created this way starts from an empty string, so the stored result is whatever the operation produces from `""`. `concat`, `append`, `prepend`, `insert`, and `overwrite` store just their operand; `pad_start` and `pad_end` store only pad text. `repeat` is the exception: repeating an empty string leaves it empty for any `count`, so the bin is created and holds `""`. It succeeds and returns no value, so that outcome is indistinguishable from a bin that was already empty.

A missing nested path behaves differently. If the path does not resolve, the operation returns `AS_ERR_OP_NOT_APPLICABLE`; the eight operations above create a missing bin, not a missing nested path. Set `NO_FAIL` to turn an unresolved path into a success that writes nothing. A malformed path returns `AS_ERR_PARAMETER` with subcode `AS_SUB_PARAM_STRING_CTX_MALFORMED`.

## Operation flags

Modify operations accept write flags per operation: a `StringWriteFlags` `int` in Java, a `StringPolicy` in Python, and an `as_string_policy` in C. Read operations take no write flags and always return an error on failure. The regex flags on [`regex_compare`](#regex_compare) and [`regex_replace`](#regex_replace), and the `numeric_type` argument on [`is_numeric`](#is_numeric), are operation arguments rather than write flags.

The policy argument precedes the context path. A positional call that omits the policy binds the context path to the policy parameter, so the operation targets the top-level bin instead of the nested string.

| Flag | Value | Effect |
| :-- | :-- | :-- |
| `CREATE_ONLY` | `0x01` | Apply the operation only if the bin does not already exist. Valid on the eight operations that [create a missing bin](#context); the other 11 modify operations reject it. Cannot be combined with `UPDATE_ONLY`, and not accepted with a context path. |
| `UPDATE_ONLY` | `0x02` | Apply the operation only if the bin already exists. Valid on all modify operations. |
| `NO_FAIL` | `0x04` | Return success and leave the bin unchanged instead of failing. Modify operations only. Read operations have no write flags. See the lists below for which failures it suppresses. |

`NO_FAIL` suppresses these failures:

-   An [`overwrite`](#overwrite) index that resolves outside the string.
-   A negative `target_length` or an empty `pad_string` on [`pad_start`](#pad_start) / [`pad_end`](#pad_end).
-   A negative `count` on [`repeat`](#repeat).
-   An empty needle on [`replace`](#replace) / [`replace_all`](#replace_all).
-   A regex pattern that fails to compile on [`regex_replace`](#regex_replace).
-   An estimated result over the [per-operation size cap](#result-size-limits).
-   A [context path](https://aerospike.com/docs/develop/data-types/collections/context) that does not resolve to a nested string.
-   `AS_ERR_BIN_EXISTS` from `CREATE_ONLY` on a bin that already exists.

`NO_FAIL` does not suppress these:

-   `AS_ERR_INCOMPATIBLE_TYPE` from applying a modify operation to a bin that is not a String.
-   `AS_ERR_INVALID_ENCODING`, either from invalid UTF-8 in the stored value or from a modify result that is not valid UTF-8.
-   Malformed or unparseable arguments, including invalid UTF-8 in an argument.
-   Write flags that are not valid for the operation: `CREATE_ONLY` on an operation that cannot create a bin, `CREATE_ONLY` together with `UPDATE_ONLY`, or `CREATE_ONLY` with a context path. Each returns `AS_ERR_PARAMETER` with subcode `AS_SUB_PARAM_STRING_OP_PARAMS_INVALID`.

Both lists contain cases that return `AS_ERR_PARAMETER`, so the error code alone does not tell you whether `NO_FAIL` would have suppressed a failure. Use the lists rather than the code.

### What a suppressed operation leaves behind

A suppressed operation leaves the bin holding the value it had before the operation ran. It does not clear the bin and does not store a null. Because modify operations return no value either way, a suppressed operation and an applied one look identical in the response. Read the bin to tell them apart.

`NO_FAIL` is not a way to modify a bin whose type you do not know. A non-String bin still returns `AS_ERR_INCOMPATIBLE_TYPE`. Gate the write with a bin-type filter expression, or handle the error.

## Reading strings

Read operations inspect or extract data from a String bin without modifying the stored value.

### Empty operands

An empty needle is an error only on [`replace`](#replace) and [`replace_all`](#replace_all). Every read operation that takes a needle answers successfully instead, treating the empty string as matching at the start of any value:

| Call | Result |
| :-- | :-- |
| [`find`](#find)`(bin, "")` | `0` |
| [`find`](#find)`("", needle)` | `-1` |
| [`contains`](#contains)`(bin, "")` | `true` |
| [`starts_with`](#starts_with)`(bin, "")` / [`ends_with`](#ends_with)`(bin, "")` | `true` |
| [`starts_with`](#starts_with)`("", prefix)` / [`ends_with`](#ends_with)`("", suffix)` | `false` |
| [`regex_compare`](#regex_compare)`(bin, "")` | `true` |

A caller that treats an empty search term as invalid input must reject it before the operation, because the server will not.

## Modifying strings

Modify operations transform the String bin in place and return no value. To read the mutated string, add a read operation for the same bin to the same `operate()` call.

The response then carries an entry for each operation on that bin, and clients differ in how an accessor reaches it: by the operation’s position, by index into a list held under the bin name, or by bin name alone, where the read’s entry replaces the modify’s. In C both entries are present, but `as_record_get` and the typed accessors answer with the first — the modify’s nil — so iterate `rec.bins.entries` to reach the value.

-   [Java SDK](#tab-panel-2686)
-   [Python SDK](#tab-panel-2687)
-   [Rust](#tab-panel-2688)
-   [C#](#tab-panel-2689)
-   [Go](#tab-panel-2690)
-   [Node.js](#tab-panel-2691)
-   [C](#tab-panel-2692)
-   [Java](#tab-panel-2693)
-   [Python](#tab-panel-2694)

```java
try (RecordStream rs = session.upsert(key)

    .bin("email").upper()

    .bin("email").get()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

    // One slot per operation, reached by position.

    String updated = rec.operationResult(1).getString();

}
```

```python
stream = session.upsert(key).bin("email").str_upper().bin("email").get().execute()

# One slot per operation, reached by position.

updated = stream.first_or_raise().record_or_raise().operation_result(1)
```

```rust
// Requires: use aerospike::operations::{scalar, string as str_op};

let rec = client.operate(&WritePolicy::default(), &key, &[

    str_op::upper(&StringPolicy::default(), "email"),

    scalar::get_bin("email"),

]).await?;

// One entry per bin name: the read's value replaces the modify's Nil.

let updated = rec.bins.get("email");
```

```csharp
Record rec = client.Operate(null, key,

    StringOperation.Upper(StringPolicy.Default, "email"),

    Operation.Get("email"));

// Both entries land in one list under the bin name, the modify's null first.

string updated = (string)rec.GetList("email")[1];
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

rec, err := client.Operate(nil, key,

    as.StrUpperOp(as.DefaultStringPolicy, "email"),

    as.GetBinOp("email"))

// Both entries land in one slice under the bin name, the modify's nil first.

updated := rec.Bins["email"].(as.OpResults)[1].(string)
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const op = Aerospike.operations

// One entry per bin name: the read's value replaces the modify's, so the

// read has to come second.

const record = await client.operate(key, [

    strings.upper('email'),

    op.read('email')

])

const updated = record.bins.email
```

```c
as_operations ops;

as_operations_init(&ops, 2);

as_operations_string_upper(&ops, "email", NULL, NULL);

as_operations_add_read(&ops, "email");

as_record* rec = NULL;

aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec);

as_operations_destroy(&ops);

// as_record_get() answers with the first entry, the modify's nil. Walk the

// entries instead and keep the last one for the bin.

const char* updated = NULL;

for (uint16_t i = 0; i < rec->bins.size; i++) {

    as_bin* b = &rec->bins.entries[i];

    if (strcmp(as_bin_get_name(b), "email") == 0) {

        as_val* v = (as_val*)as_bin_get_value(b);

        if (as_val_type(v) == AS_STRING) updated = as_string_get((as_string*)v);

    }

}
```

```java
Record rec = client.operate(null, key,

    StringOperation.upper(StringPolicy.Default, "email"),

    Operation.get("email"));

// Both entries land in one list under the bin name, the modify's null first.

String updated = (String) rec.getList("email").get(1);
```

```python
from aerospike_helpers.operations import operations, string_operations as so

# One entry per bin name: the read's value replaces the modify's None, so the

# read has to come second.

_, _, bins = client.operate(key, [

    so.upper("email"),

    operations.read("email"),

])

updated = bins["email"]
```

[`to_string`](#to_string) is the exception: it dispatches as a read operation and does return the converted string.

### Result size limits

Two separate limits apply to a modify operation, and they fail differently:

-   **Per-operation result cap: 8 MiB.** A modify operation whose result would exceed 8 MiB fails with `AS_ERR_PARAMETER` (subcode `AS_SUB_PARAM_STRING_OP_PARAMS_INVALID`) before it runs. The limit is applied to an upper-bound estimate rather than to the finished string, so an operation can be rejected when its actual result would have fit.
-   **Record size limit.** A result that clears the per-operation cap is then subject to the namespace [`max-record-size`](https://aerospike.com/docs/database/reference/config#namespace__max-record-size) when the record is written, which fails with `AS_ERR_RECORD_TOO_BIG`.

The per-operation cap is checked first, so an oversized transform surfaces as a parameter error rather than a record-size error. Setting `NO_FAIL` suppresses that rejection: the operation returns success and the bin keeps its previous value, so a write that was too large to apply is indistinguishable from one that succeeded.

A `doc` bin holding 1 KiB repeated 10,000 times would pass 8 MiB. With `NO_FAIL` set, each of these calls succeeds and leaves `doc` at its original 1 KiB:

-   [Java SDK](#tab-panel-2695)
-   [Python SDK](#tab-panel-2696)
-   [Rust](#tab-panel-2697)
-   [C#](#tab-panel-2698)
-   [Go](#tab-panel-2699)
-   [Node.js](#tab-panel-2700)
-   [C](#tab-panel-2701)
-   [Java](#tab-panel-2702)
-   [Python](#tab-panel-2703)

```java
try (RecordStream rs = session.upsert(key)

    .bin("doc").repeat(10000, StringWriteOptions::noFail)

    .execute()) {

    rs.next().recordOrThrow();

}
```

```python
from aerospike_sdk import StringWriteFlags

session.upsert(key).bin("doc").str_repeat(

    10000, flags=StringWriteFlags.NO_FAIL).execute()
```

```rust
// Requires: use aerospike::operations::string::{self as str_op, StringPolicy, StringWriteFlags};

client.operate(&WritePolicy::default(), &key, &[

    str_op::repeat(&StringPolicy::new(StringWriteFlags::NO_FAIL), "doc", 10000),

]).await?;
```

```csharp
client.Operate(null, key, StringOperation.Repeat(

    new StringPolicy(StringWriteFlags.NO_FAIL), "doc", 10000));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrRepeatOp(as.NewStringPolicy(as.StringWriteNoFail), "doc", 10000))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [

    strings.repeat('doc', 10000)

        .withPolicy({ writeFlags: strings.writeFlags.NO_FAIL })

])
```

```c
as_string_policy policy;

as_string_policy_init(&policy);

as_string_policy_set(&policy, AS_STRING_WRITE_FLAGS_NO_FAIL);

as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_repeat(&ops, "doc", NULL, &policy, 10000);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key, StringOperation.repeat(

    new StringPolicy(StringWriteFlags.NO_FAIL), "doc", 10000));
```

```python
from aerospike_helpers.operations import string_operations as so

from aerospike_helpers.string_helpers import StringPolicy, WriteFlags

client.operate(key, [

    so.repeat("doc", 10000, StringPolicy(WriteFlags.NO_FAIL)),

])
```

Without `NO_FAIL`, the same call fails with `AS_ERR_PARAMETER`, which is the only signal that the transform did not happen.

## Converting to string

[`to_string`](#to_string) converts integer, float, boolean, blob, or string bins to a string representation without requiring the client to know the bin type in advance.

## Error codes

| Error | Typical cause |
| :-- | :-- |
| `AS_ERR_INCOMPATIBLE_TYPE` | Operation applied to a non-String bin (or wrong type for `to_string`) |
| `AS_ERR_INVALID_ENCODING` | String bin contains invalid UTF-8 at operation time |
| `AS_ERR_PARAMETER` | Invalid argument: invalid UTF-8 in an operation argument, an invalid or [rejected](https://aerospike.com/docs/develop/data-types/string/regex-syntax#non-icu-constructs-rejected-at-parse-time) regex pattern, an unrecognized regex flag bit, a write flag that is not valid for the operation, an empty needle on [`replace`](#replace) or [`replace_all`](#replace_all), a negative repeat count or pad length, an out-of-range [`overwrite`](#overwrite) index, or a result that would exceed the [per-operation size limit](#result-size-limits) |
| `AS_ERR_OP_NOT_APPLICABLE` | Operation cannot be applied to this value: a numeric parse failure or overflow, [`to_string`](#to_string) on a non-UTF-8 blob, invalid base64, or a [regex complexity limit](https://aerospike.com/docs/develop/data-types/string/regex-syntax#resource-limits) |
| `AS_ERR_BIN_EXISTS` | The bin already exists and the operation carries `CREATE_ONLY` |
| `AS_ERR_RECORD_TOO_BIG` | The written record exceeds the [`max-record-size`](https://aerospike.com/docs/database/reference/config#namespace__max-record-size) limit |

The same errors can surface when string bin [expressions](https://aerospike.com/docs/develop/expressions/string) run in filters or `operate` projections. Filter expressions that evaluate to `unknown` exclude the record from query results.

See [Error codes](https://aerospike.com/docs/database/reference/error-codes) for the full list.

### Error detail subcodes

When a client asks for error details, a failure carries a machine-readable subcode alongside the human-readable message. The `error-details-max-verbosity` service configuration parameter caps how much detail the server returns. Each subcode belongs to exactly one status, and published values are never renumbered or reused, so you can match on them.

Subcodes paired with `AS_ERR_PARAMETER`:

| Subcode | Value | Condition |
| :-- | :-- | :-- |
| `AS_SUB_PARAM_STRING_OP_PARAMS_INVALID` | 6 | Arguments malformed or out of range, including invalid regex flag bits |
| `AS_SUB_PARAM_STRING_OP_INVALID` | 7 | Unrecognized operation code, or a read operation sent on the modify path |
| `AS_SUB_PARAM_STRING_CTX_MALFORMED` | 8 | Malformed [context path](#context) |
| `AS_SUB_PARAM_STRING_INDEX_OUT_OF_BOUNDS` | 9 | Index or codepoint range out of bounds, as with [`overwrite`](#overwrite) |
| `AS_SUB_PARAM_STRING_REGEX_INVALID` | 10 | Regex pattern is not valid ICU syntax |
| `AS_SUB_PARAM_STRING_UTF8_INVALID` | 11 | A string argument is not valid UTF-8 |

Subcodes paired with `AS_ERR_OP_NOT_APPLICABLE`:

| Subcode | Value | Condition |
| :-- | :-- | :-- |
| `AS_SUB_OPNOT_STRING_CONVERSION_FAILED` | 10 | [`to_integer`](#to_integer) or [`to_double`](#to_double) could not parse the string, including numeric overflow |
| `AS_SUB_OPNOT_STRING_UTF8_INVALID` | 11 | Source blob or string is not valid UTF-8 |
| `AS_SUB_OPNOT_STRING_REGEX_LIMIT_EXCEEDED` | 12 | Regex match or replace exhausted an engine budget |
| `AS_SUB_OPNOT_STRING_B64_INVALID` | 13 | Value is not valid base64 |

Failures that the status alone identifies, such as `AS_ERR_INCOMPATIBLE_TYPE`, report `AS_SUB_NONE` (0) and carry the distinguishing detail in the message text.

## Modify operations

#### `append`

`create_only` `update_only` `no_fail`

```python
append(bin, value[, policy][, context])
```

Description: Appends `value` to the string bin (Unicode-aware).

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `value` | `string` | 

Text to append.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_append`](https://aerospike.com/docs/develop/expressions/string#string_append)

Examples: Append to the end

A record stores a running log line in a String bin called `log`. Given `log = "start"`, calling `append("log", " line")` leaves the bin holding `"start line"`.

Code sample: -   [Java SDK](#tab-panel-2704)
-   [Python SDK](#tab-panel-2705)
-   [Rust](#tab-panel-2706)
-   [C#](#tab-panel-2707)
-   [Go](#tab-panel-2708)
-   [Node.js](#tab-panel-2709)
-   [C](#tab-panel-2710)
-   [Java](#tab-panel-2711)
-   [Python](#tab-panel-2712)

```java
try (RecordStream rs = session.upsert(key)

    .bin("log").append(" line")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("log").str_append(" line").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::append(&StringPolicy::default(), "log", " line")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Append(StringPolicy.Default, "log", " line"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrAppendOp(as.DefaultStringPolicy, "log", " line"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.append('log', ' line')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_append(&ops, "log", NULL, NULL, " line");

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.append(StringPolicy.Default, "log", " line"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.append("log", " line")])
```

---

#### `case_fold`

`update_only` `no_fail`

```python
case_fold(bin[, policy][, context])
```

Description: Applies Unicode case folding for case-insensitive comparison.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_case_fold`](https://aerospike.com/docs/develop/expressions/string#string_case_fold)

Examples: Fold case for comparison

Case folding normalizes a value for caseless comparison, and is not the same as lowercasing. Given `name = "Straße"`, calling `case_fold("name")` leaves the bin holding `"strasse"`: the sharp s expands to two characters, so the string gets longer.

Code sample: -   [Java SDK](#tab-panel-2713)
-   [Python SDK](#tab-panel-2714)
-   [Rust](#tab-panel-2715)
-   [C#](#tab-panel-2716)
-   [Go](#tab-panel-2717)
-   [Node.js](#tab-panel-2718)
-   [C](#tab-panel-2719)
-   [Java](#tab-panel-2720)
-   [Python](#tab-panel-2721)

```java
try (RecordStream rs = session.upsert(key)

    .bin("name").caseFold()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("name").str_case_fold().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::case_fold(&StringPolicy::default(), "name")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.CaseFold(StringPolicy.Default, "name"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrCaseFoldOp(as.DefaultStringPolicy, "name"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.caseFold('name')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_case_fold(&ops, "name", NULL, NULL);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.caseFold(StringPolicy.Default, "name"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.casefold("name")])
```

---

#### `concat`

`create_only` `update_only` `no_fail`

```python
concat(bin, value[, policy][, context])
```

Description: Concatenates additional string values onto the bin.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `value` | `string` | 

String values to append to the bin, in order. The server operation takes a list. Python accepts a list only, and Java and C also provide a single-value form.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_concat`](https://aerospike.com/docs/develop/expressions/string#string_concat)

Examples: Join a fragment onto the value

A record stores a label list in a String bin called `tags`. Given `tags = "red"`, calling `concat("tags", ",green")` leaves the bin holding `"red,green"`.

Code sample: -   [Java SDK](#tab-panel-2722)
-   [Python SDK](#tab-panel-2723)
-   [Rust](#tab-panel-2724)
-   [C#](#tab-panel-2725)
-   [Go](#tab-panel-2726)
-   [Node.js](#tab-panel-2727)
-   [C](#tab-panel-2728)
-   [Java](#tab-panel-2729)
-   [Python](#tab-panel-2730)

```java
try (RecordStream rs = session.upsert(key)

    .bin("tags").concat(",green")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("tags").str_concat([",green"]).execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::concat(&StringPolicy::default(), "tags", ",green")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Concat(StringPolicy.Default, "tags", ",green"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrConcatOp(as.DefaultStringPolicy, "tags", ",green"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.concat('tags', ',green')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_concat(&ops, "tags", NULL, NULL, ",green");

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.concat(StringPolicy.Default, "tags", ",green"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.concat("tags", [",green"])])
```

---

#### `insert`

`create_only` `update_only` `no_fail`

```python
insert(bin, offset, value[, policy][, context])
```

Description: Inserts `value` at codepoint `offset`.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `offset` | `integer` | 

Codepoint index at which to insert. Negative values count from the end of the string. Out-of-range values are clamped to `[0, length]`, so an offset equal to the length appends.

 |
| `value` | `string` | 

Text to insert.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_insert`](https://aerospike.com/docs/develop/expressions/string#string_insert)

Examples: Insert at a codepoint offset

Given `text = "hi"`, calling `insert("text", 1, "oh")` leaves the bin holding `"hohi"`. The offset is a codepoint index, so the new text lands before the character currently at that position.

Code sample: -   [Java SDK](#tab-panel-2731)
-   [Python SDK](#tab-panel-2732)
-   [Rust](#tab-panel-2733)
-   [C#](#tab-panel-2734)
-   [Go](#tab-panel-2735)
-   [Node.js](#tab-panel-2736)
-   [C](#tab-panel-2737)
-   [Java](#tab-panel-2738)
-   [Python](#tab-panel-2739)

```java
try (RecordStream rs = session.upsert(key)

    .bin("text").insert(1, "oh")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("text").str_insert(1, "oh").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::insert(&StringPolicy::default(), "text", 1, "oh")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Insert(StringPolicy.Default, "text", 1, "oh"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrInsertOp(as.DefaultStringPolicy, "text", 1, "oh"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.insert('text', 1, 'oh')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_insert(&ops, "text", NULL, NULL, 1, "oh");

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.insert(StringPolicy.Default, "text", 1, "oh"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.insert("text", 1, "oh")])
```

---

#### `lower`

`update_only` `no_fail`

```python
lower(bin[, policy][, context])
```

Description: Converts the String bin to lowercase.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_lower`](https://aerospike.com/docs/develop/expressions/string#string_lower)

Examples: Lowercase a value

A record stores an address a user typed into a form, in a String bin called `email`. Given `email = "Ana@Corp.IO"`, calling `lower("email")` leaves the bin holding `"ana@corp.io"`.

Code sample: -   [Java SDK](#tab-panel-2740)
-   [Python SDK](#tab-panel-2741)
-   [Rust](#tab-panel-2742)
-   [C#](#tab-panel-2743)
-   [Go](#tab-panel-2744)
-   [Node.js](#tab-panel-2745)
-   [C](#tab-panel-2746)
-   [Java](#tab-panel-2747)
-   [Python](#tab-panel-2748)

```java
try (RecordStream rs = session.upsert(key)

    .bin("email").lower()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("email").str_lower().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::lower(&StringPolicy::default(), "email")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Lower(StringPolicy.Default, "email"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrLowerOp(as.DefaultStringPolicy, "email"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.lower('email')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_lower(&ops, "email", NULL, NULL);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.lower(StringPolicy.Default, "email"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.lower("email")])
```

---

#### `normalize_nfc`

`update_only` `no_fail`

```python
normalize_nfc(bin[, policy][, context])
```

Description: Normalizes the String bin to Unicode NFC form. Normalize stored values before comparing them with NFC literals using the `eq` expression. See [Compare String values](https://aerospike.com/develop/data-types/string/comparison).

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_normalize_nfc`](https://aerospike.com/docs/develop/expressions/string#string_normalize_nfc)

Examples: Normalize to composed form

The same text can be stored two ways: a precomposed `é` (U+00E9), or an `e` followed by a combining acute accent (U+0301). Given `name` holding the two-codepoint decomposed form, calling `normalize_nfc("name")` leaves the bin holding the single precomposed codepoint, so `strlen` drops from `2` to `1`.

Code sample: -   [Java SDK](#tab-panel-2749)
-   [Python SDK](#tab-panel-2750)
-   [Rust](#tab-panel-2751)
-   [C#](#tab-panel-2752)
-   [Go](#tab-panel-2753)
-   [Node.js](#tab-panel-2754)
-   [C](#tab-panel-2755)
-   [Java](#tab-panel-2756)
-   [Python](#tab-panel-2757)

```java
try (RecordStream rs = session.upsert(key)

    .bin("name").normalizeNfc()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("name").str_normalize_nfc().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::normalize_nfc(&StringPolicy::default(), "name")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.NormalizeNFC(StringPolicy.Default, "name"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrNormalizeNFCOp(as.DefaultStringPolicy, "name"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.normalizeNfc('name')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_normalize_nfc(&ops, "name", NULL, NULL);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.normalizeNFC(StringPolicy.Default, "name"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.normalize_nfc("name")])
```

---

#### `overwrite`

`create_only` `update_only` `no_fail`

```python
overwrite(bin, offset, value[, policy][, context])
```

Description: Overwrites the string bin starting at codepoint `offset` with `value`.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `offset` | `integer` | 

Codepoint index at which to start overwriting. Negative values count from the end of the string, as they do for `insert`, `char_at`, `substr`, and `snip`. The resolved index must satisfy `0 <= offset < length`; outside that range the operation returns `AS_ERR_PARAMETER` with subcode `AS_SUB_PARAM_STRING_INDEX_OUT_OF_BOUNDS` rather than being clamped. Unlike `insert`, `overwrite` cannot target an offset equal to the string length, because it carries no fill text for the gap that would leave. On an empty or missing bin the only accepted offset is `0`, which writes `value` as the new bin contents.

 |
| `value` | `string` | 

Replacement text.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_overwrite`](https://aerospike.com/docs/develop/expressions/string#string_overwrite)

Examples: Replace text at a fixed position

Given `text = "2026-01-01"`, calling `overwrite("text", 5, "12")` leaves the bin holding `"2026-12-01"`. The replacement is written in place and the string length does not change.

Code sample: -   [Java SDK](#tab-panel-2758)
-   [Python SDK](#tab-panel-2759)
-   [Rust](#tab-panel-2760)
-   [C#](#tab-panel-2761)
-   [Go](#tab-panel-2762)
-   [Node.js](#tab-panel-2763)
-   [C](#tab-panel-2764)
-   [Java](#tab-panel-2765)
-   [Python](#tab-panel-2766)

```java
try (RecordStream rs = session.upsert(key)

    .bin("text").overwrite(5, "12")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("text").str_overwrite(5, "12").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::overwrite(&StringPolicy::default(), "text", 5, "12")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Overwrite(StringPolicy.Default, "text", 5, "12"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrOverwriteOp(as.DefaultStringPolicy, "text", 5, "12"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.overwrite('text', 5, '12')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_overwrite(&ops, "text", NULL, NULL, 5, "12");

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.overwrite(StringPolicy.Default, "text", 5, "12"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.overwrite("text", 5, "12")])
```

---

#### `pad_end`

`create_only` `update_only` `no_fail`

```python
pad_end(bin, target_length, pad_string[, policy][, context])
```

Description: Pads the end of the string bin to `target_length` using `pad_string`.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `target_length` | `integer` | 

Minimum codepoint length after padding. Must be non-negative. Padding adds exactly enough codepoints to reach this length.

 |
| `pad_string` | `string` | 

Padding string. Must not be empty. A multi-codepoint pad repeats to fill the gap and is truncated mid-pattern to reach `target_length` exactly, so padding `"xyz"` to 8 with `"ab"` yields `"xyzababa"`.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_pad_end`](https://aerospike.com/docs/develop/expressions/string#string_pad_end)

Examples: Pad to a fixed width

Given `id = "42"`, calling `pad_end("id", 6, "0")` leaves the bin holding `"420000"`. A value already at or beyond the target length is left unchanged.

---

Padding shorter than a whole repetition

The pad repeats whole, then a prefix of it fills the remainder. Padding `"xyz"` to 8 codepoints with `"ab"` needs 5 pad codepoints, so the pad block is `"ab" + "ab" + "a"` and the result is `"xyzababa"`. The truncated fragment lands at the end of the string, not next to the original text.

A negative `target_length` or an empty `pad_string` returns `AS_ERR_PARAMETER` with subcode `AS_SUB_PARAM_STRING_OP_PARAMS_INVALID`.

Code sample: -   [Java SDK](#tab-panel-2767)
-   [Python SDK](#tab-panel-2768)
-   [Rust](#tab-panel-2769)
-   [C#](#tab-panel-2770)
-   [Go](#tab-panel-2771)
-   [Node.js](#tab-panel-2772)
-   [C](#tab-panel-2773)
-   [Java](#tab-panel-2774)
-   [Python](#tab-panel-2775)

```java
try (RecordStream rs = session.upsert(key)

    .bin("id").padEnd(6, "0")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("id").str_pad_end(6, "0").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::pad_end(&StringPolicy::default(), "id", 6, "0")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.PadEnd(StringPolicy.Default, "id", 6, "0"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrPadEndOp(as.DefaultStringPolicy, "id", 6, "0"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.padEnd('id', 6, '0')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_pad_end(&ops, "id", NULL, NULL, 6, "0");

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.padEnd(StringPolicy.Default, "id", 6, "0"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.pad_end("id", 6, "0")])
```

---

#### `pad_start`

`create_only` `update_only` `no_fail`

```python
pad_start(bin, target_length, pad_string[, policy][, context])
```

Description: Pads the start of the string bin to `target_length` using `pad_string`.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `target_length` | `integer` | 

Minimum codepoint length after padding. Must be non-negative. Padding adds exactly enough codepoints to reach this length.

 |
| `pad_string` | `string` | 

Padding string. Must not be empty. A multi-codepoint pad repeats to fill the gap and is truncated mid-pattern to reach `target_length` exactly, so padding `"xyz"` to 8 with `"ab"` yields `"ababaxyz"`.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_pad_start`](https://aerospike.com/docs/develop/expressions/string#string_pad_start)

Examples: Pad to a fixed width

Given `id = "42"`, calling `pad_start("id", 6, "0")` leaves the bin holding `"000042"`. A value already at or beyond the target length is left unchanged.

---

Padding shorter than a whole repetition

The pad repeats whole, then a prefix of it fills the remainder. Padding `"xyz"` to 8 codepoints with `"ab"` needs 5 pad codepoints, so the pad block is `"ab" + "ab" + "a"` and the result is `"ababaxyz"`. [`pad_end`](#pad_end) builds the same block and appends it instead, giving `"xyzababa"`.

A negative `target_length` or an empty `pad_string` returns `AS_ERR_PARAMETER` with subcode `AS_SUB_PARAM_STRING_OP_PARAMS_INVALID`.

Code sample: -   [Java SDK](#tab-panel-2776)
-   [Python SDK](#tab-panel-2777)
-   [Rust](#tab-panel-2778)
-   [C#](#tab-panel-2779)
-   [Go](#tab-panel-2780)
-   [Node.js](#tab-panel-2781)
-   [C](#tab-panel-2782)
-   [Java](#tab-panel-2783)
-   [Python](#tab-panel-2784)

```java
try (RecordStream rs = session.upsert(key)

    .bin("id").padStart(6, "0")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("id").str_pad_start(6, "0").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::pad_start(&StringPolicy::default(), "id", 6, "0")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.PadStart(StringPolicy.Default, "id", 6, "0"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrPadStartOp(as.DefaultStringPolicy, "id", 6, "0"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.padStart('id', 6, '0')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_pad_start(&ops, "id", NULL, NULL, 6, "0");

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.padStart(StringPolicy.Default, "id", 6, "0"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.pad_start("id", 6, "0")])
```

---

#### `prepend`

`create_only` `update_only` `no_fail`

```python
prepend(bin, value[, policy][, context])
```

Description: Prepends `value` to the string bin (Unicode-aware).

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `value` | `string` | 

Text to prepend.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_prepend`](https://aerospike.com/docs/develop/expressions/string#string_prepend)

Examples: Prepend to the front

A record stores a log line in a String bin called `log`. Given `log = "started"`, calling `prepend("log", "prefix: ")` leaves the bin holding `"prefix: started"`.

Code sample: -   [Java SDK](#tab-panel-2785)
-   [Python SDK](#tab-panel-2786)
-   [Rust](#tab-panel-2787)
-   [C#](#tab-panel-2788)
-   [Go](#tab-panel-2789)
-   [Node.js](#tab-panel-2790)
-   [C](#tab-panel-2791)
-   [Java](#tab-panel-2792)
-   [Python](#tab-panel-2793)

```java
try (RecordStream rs = session.upsert(key)

    .bin("log").prepend("prefix: ")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("log").str_prepend("prefix: ").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::prepend(&StringPolicy::default(), "log", "prefix: ")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Prepend(StringPolicy.Default, "log", "prefix: "));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrPrependOp(as.DefaultStringPolicy, "log", "prefix: "))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.prepend('log', 'prefix: ')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_prepend(&ops, "log", NULL, NULL, "prefix: ");

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.prepend(StringPolicy.Default, "log", "prefix: "));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.prepend("log", "prefix: ")])
```

---

#### `regex_replace`

`update_only` `no_fail`

```python
regex_replace(bin, pattern, replacement[, regex_flags][, policy][, context])
```

Description: Replaces the first regex match in the string bin, or every match when the `GLOBAL` flag is set.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `pattern` | `string` | 

Regular expression pattern. An empty pattern is accepted rather than rejected, and matches at every position: without `GLOBAL` the replacement is prepended to the value, and with `GLOBAL` it is inserted before every codepoint and once at the end. This differs from [`replace`](#replace) and [`replace_all`](#replace_all), which reject an empty needle. For the syntax the pattern is written in, see [Regular expression syntax](https://aerospike.com/docs/develop/data-types/string/regex-syntax).

 |
| `replacement` | `string` | 

Replacement text, in ICU’s replacement dialect: `$0` is the whole match, `$1` a numbered capture group, `${name}` a named one, and `\` escapes the next character. A `$` that resolves to no capture group fails the operation on any record the pattern matches; where it does not match, the replacement is never evaluated and the operation succeeds unchanged. See [Replacement string syntax](https://aerospike.com/docs/develop/data-types/string/regex-syntax#replacement-string-syntax).

 |
| `regex_flags` | `integer` | 

Regex flags, combined with bitwise OR. Defaults to none, which replaces only the first match; `GLOBAL` (16) replaces every match and is valid on this operation only. For the values, their effects, how AEL spells them, and why these must not be confused with the string write flags, see [Regex flags](https://aerospike.com/docs/develop/data-types/string/regex-syntax#flags). The write policy is a separate argument.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_regex_replace`](https://aerospike.com/docs/develop/expressions/string#string_regex_replace)

Examples: Replace every match

Without `GLOBAL`, only the first match is replaced: on `"a1 b22 c333"`, stripping `\d+` yields `"a b22 c333"`. Setting `GLOBAL` yields `"a b c"`.

Modify operations do not return a value. To read the result, add a read operation for the same bin to the same `operate()` call.

---

Passing a policy needs all three arguments

Regex flags and the write policy are [different sets](https://aerospike.com/docs/develop/data-types/string/regex-syntax#reads-and-writes-take-different-flags), and passing one where the other belongs is silent. Beyond that, there is no 2-arg form for policy alone. The second wire argument is always consumed as `regex_flags`. To pass `NO_FAIL` (or any policy flag), send all three arguments and include `regex_flags` explicitly, using `0` when no regex behavior is wanted. A 1- or 2-arg send is safe when no policy is needed.

Code sample: -   [Java SDK](#tab-panel-2794)
-   [Python SDK](#tab-panel-2795)
-   [Rust](#tab-panel-2796)
-   [C#](#tab-panel-2797)
-   [Go](#tab-panel-2798)
-   [Node.js](#tab-panel-2799)
-   [C](#tab-panel-2800)
-   [Java](#tab-panel-2801)
-   [Python](#tab-panel-2802)

```java
try (RecordStream rs = session.upsert(key)

    .bin("text").regexReplace("\\d+", "", StringRegexFlags.GLOBAL)

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("text").str_regex_replace(

    r"\d+", "", StringRegexFlags.GLOBAL).execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::regex_replace(&StringPolicy::default(), "text", r"\d+", "",

        StringRegexFlags::GLOBAL)]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.RegexReplace(StringPolicy.Default, "text", @"\d+", "",

        StringRegexFlags.GLOBAL));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrRegexReplaceOp(as.DefaultStringPolicy, "text", `\d+`, "", as.StringRegexGlobal))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [

    strings.regexReplace('text', '\\d+', '', strings.regexFlags.GLOBAL)

])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_regex_replace(&ops, "text", NULL, NULL, "\\d+", "",

    AS_STRING_REGEX_FLAGS_GLOBAL);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.regexReplace(StringPolicy.Default, "text", "\\d+", "",

        StringRegexFlags.GLOBAL));
```

```python
from aerospike_helpers.operations import string_operations as so

from aerospike_helpers.string_helpers import RegexFlags

client.operate(key, [so.regex_replace("text", r"\d+", "", RegexFlags.GLOBAL)])
```

---

#### `repeat`

`create_only` `update_only` `no_fail`

```python
repeat(bin, count[, policy][, context])
```

Description: Repeats the string bin `count` times.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `count` | `integer` | 

Number of times to repeat the bin value. Must be non-negative. A negative `count` returns `AS_ERR_PARAMETER`. A `count` of `0` is accepted and is not a no-op: it replaces the bin value with the empty string.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_repeat`](https://aerospike.com/docs/develop/expressions/string#string_repeat)

Examples: Repeat the value

Given `unit = "ab"`, calling `repeat("unit", 3)` leaves the bin holding `"ababab"`. A count of `1` leaves the value unchanged.

---

A count of zero empties the bin

`repeat(bin, 0)` succeeds and writes the empty string. The bin stays present and holds `""`. It is not left unchanged and it is not removed. Guard the call if `count` comes from application input that can reach zero.

Modify operations do not return a value. To read the new string, add a read operation for the same bin to the same `operate()` call.

Code sample: -   [Java SDK](#tab-panel-2803)
-   [Python SDK](#tab-panel-2804)
-   [Rust](#tab-panel-2805)
-   [C#](#tab-panel-2806)
-   [Go](#tab-panel-2807)
-   [Node.js](#tab-panel-2808)
-   [C](#tab-panel-2809)
-   [Java](#tab-panel-2810)
-   [Python](#tab-panel-2811)

```java
try (RecordStream rs = session.upsert(key)

    .bin("unit").repeat(3)

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("unit").str_repeat(3).execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::repeat(&StringPolicy::default(), "unit", 3)]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Repeat(StringPolicy.Default, "unit", 3));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrRepeatOp(as.DefaultStringPolicy, "unit", 3))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.repeat('unit', 3)])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_repeat(&ops, "unit", NULL, NULL, 3);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.repeat(StringPolicy.Default, "unit", 3));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.repeat("unit", 3)])
```

---

#### `replace`

`update_only` `no_fail`

```python
replace(bin, find, replace[, policy][, context])
```

Description: Replaces the first occurrence of `find` with `replace`. Treats canonically equivalent text as equal.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `find` | `string` | 

Substring to replace. Must not be empty: an empty needle returns `AS_ERR_PARAMETER`. [`regex_replace`](#regex_replace) differs, accepting an empty pattern and rewriting the value.

 |
| `replace` | `string` | 

Replacement text.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_replace`](https://aerospike.com/docs/develop/expressions/string#string_replace)

Examples: Rewrite the first match

A record stores a file location in a String bin called `path`. Given `path = "/data/tmp/data.log"`, calling `replace("path", "/data", "/mnt")` sets the bin to `"/mnt/tmp/data.log"`. The needle occurs twice and only the leading occurrence changes. Use [`replace_all`](#replace_all) to change every occurrence.

Modify operations do not return a value. To read the new string, add a read operation for the same bin to the same `operate()` call.

---

A needle that is absent still succeeds

A `find` value that does not occur in the string is not a miss to report: the operation returns success and leaves the value unchanged. Because modify operations return no value, that outcome is indistinguishable from a replacement that happened. Read the bin in the same `operate()` call when the caller needs to know whether anything changed.

Code sample: -   [Java SDK](#tab-panel-2812)
-   [Python SDK](#tab-panel-2813)
-   [Rust](#tab-panel-2814)
-   [C#](#tab-panel-2815)
-   [Go](#tab-panel-2816)
-   [Node.js](#tab-panel-2817)
-   [C](#tab-panel-2818)
-   [Java](#tab-panel-2819)
-   [Python](#tab-panel-2820)

```java
try (RecordStream rs = session.upsert(key)

    .bin("path").replace("/data", "/mnt")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("path").str_replace("/data", "/mnt").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::replace(&StringPolicy::default(), "path", "/data", "/mnt")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Replace(StringPolicy.Default, "path", "/data", "/mnt"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrReplaceOp(as.DefaultStringPolicy, "path", "/data", "/mnt"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.replace('path', '/data', '/mnt')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_replace(&ops, "path", NULL, NULL, "/data", "/mnt");

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.replace(StringPolicy.Default, "path", "/data", "/mnt"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.replace("path", "/data", "/mnt")])
```

---

#### `replace_all`

`update_only` `no_fail`

```python
replace_all(bin, find, replace[, policy][, context])
```

Description: Replaces all occurrences of `find` with `replace`. Treats canonically equivalent text as equal.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `find` | `string` | 

Substring to replace. Must not be empty: an empty needle returns `AS_ERR_PARAMETER`. [`regex_replace`](#regex_replace) differs, accepting an empty pattern and rewriting the value.

 |
| `replace` | `string` | 

Replacement text.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_replace_all`](https://aerospike.com/docs/develop/expressions/string#string_replace_all)

Examples: Rewrite every match

A record stores a file location in a String bin called `path`. Given `path = "/data/tmp/data.log"`, calling `replace_all("path", "/data", "/mnt")` sets the bin to `"/mnt/tmp/mnt.log"`, changing both occurrences. Use [`replace`](#replace) to change only the first.

Modify operations do not return a value. To read the new string, add a read operation for the same bin to the same `operate()` call.

---

A needle that is absent still succeeds

A `find` value that does not occur in the string is not a miss to report: the operation returns success and leaves the value unchanged. Because modify operations return no value, that outcome is indistinguishable from a replacement that happened. Read the bin in the same `operate()` call when the caller needs to know whether anything changed.

Code sample: -   [Java SDK](#tab-panel-2821)
-   [Python SDK](#tab-panel-2822)
-   [Rust](#tab-panel-2823)
-   [C#](#tab-panel-2824)
-   [Go](#tab-panel-2825)
-   [Node.js](#tab-panel-2826)
-   [C](#tab-panel-2827)
-   [Java](#tab-panel-2828)
-   [Python](#tab-panel-2829)

```java
try (RecordStream rs = session.upsert(key)

    .bin("path").replaceAll("/data", "/mnt")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("path").str_replace_all("/data", "/mnt").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::replace_all(&StringPolicy::default(), "path", "/data", "/mnt")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.ReplaceAll(StringPolicy.Default, "path", "/data", "/mnt"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrReplaceAllOp(as.DefaultStringPolicy, "path", "/data", "/mnt"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.replaceAll('path', '/data', '/mnt')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_replace_all(&ops, "path", NULL, NULL, "/data", "/mnt");

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.replaceAll(StringPolicy.Default, "path", "/data", "/mnt"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.replace_all("path", "/data", "/mnt")])
```

---

#### `snip`

`update_only` `no_fail`

```python
snip(bin, from[, to][, policy][, context])
```

Description: Removes the codepoint range from `from` (inclusive) to `to` (exclusive).

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `from` | `integer` | 

Start codepoint index (inclusive). Negative values count from the end of the string. Out-of-range values are clamped to `[0, length]`.

 |
| `to` | `integer` | 

End codepoint index (exclusive). Negative values count from the end of the string; out-of-range values are clamped to `[0, length]`. Optional; defaults to the string’s codepoint length, removing everything from `from` to the end of the string. Omitting `to` also drops the write flags: the shorter form carries no policy, so `NO_FAIL` has no effect on it. Pass `to` explicitly when the operation needs a flag, and use the string’s length to keep the same result.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_snip`](https://aerospike.com/docs/develop/expressions/string#string_snip)

Examples: Remove a codepoint range

Given `text = "hello big world"`, calling `snip("text", 6, 10)` leaves the bin holding `"hello world"`. The range is half-open, so the codepoint at `to` is kept.

Code sample: -   [Java SDK](#tab-panel-2830)
-   [Python SDK](#tab-panel-2831)
-   [Rust](#tab-panel-2832)
-   [C#](#tab-panel-2833)
-   [Go](#tab-panel-2834)
-   [Node.js](#tab-panel-2835)
-   [C](#tab-panel-2836)
-   [Java](#tab-panel-2837)
-   [Python](#tab-panel-2838)

```java
try (RecordStream rs = session.upsert(key)

    .bin("text").snip(6, 10)

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("text").str_snip(6, 10).execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::snip(&StringPolicy::default(), "text", 6, 10)]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Snip(StringPolicy.Default, "text", 6, 10));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrSnipOp(as.DefaultStringPolicy, "text", 6, 10))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.snip('text', 6, 10)])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_snip(&ops, "text", NULL, NULL, 6, 10);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.snip(StringPolicy.Default, "text", 6, 10));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.snip("text", 6, 10)])
```

---

#### `trim`

`update_only` `no_fail`

```python
trim(bin[, policy][, context])
```

Description: Removes leading and trailing Unicode whitespace.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_trim`](https://aerospike.com/docs/develop/expressions/string#string_trim)

Examples: Strip surrounding whitespace

A record stores an address a user typed into a form, in a String bin called `email`. Trimming it server-side normalizes the value without a read and a rewrite.

Given `email = " ana@corp.io "`, calling `trim("email")` leaves the bin holding `"ana@corp.io"`. Use [`trim_start`](#trim_start) or [`trim_end`](#trim_end) to strip only one side.

Modify operations do not return a value. To read the trimmed string, add a read operation for the same bin to the same `operate()` call.

---

Whitespace is the full Unicode set

`trim` strips every codepoint carrying the Unicode `White_Space` property, not only spaces and tabs. That includes the no-break space (U+00A0), the figure space (U+2007), and the narrow no-break space (U+202F), so text pasted from a web page or a word processor loses those too.

A value that is entirely whitespace becomes the empty string rather than staying unchanged.

Code sample: -   [Java SDK](#tab-panel-2839)
-   [Python SDK](#tab-panel-2840)
-   [Rust](#tab-panel-2841)
-   [C#](#tab-panel-2842)
-   [Go](#tab-panel-2843)
-   [Node.js](#tab-panel-2844)
-   [C](#tab-panel-2845)
-   [Java](#tab-panel-2846)
-   [Python](#tab-panel-2847)

```java
try (RecordStream rs = session.upsert(key)

    .bin("email").trim()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("email").str_trim().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::trim(&StringPolicy::default(), "email")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Trim(StringPolicy.Default, "email"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrTrimOp(as.DefaultStringPolicy, "email"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.trim('email')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_trim(&ops, "email", NULL, NULL);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.trim(StringPolicy.Default, "email"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.trim("email")])
```

---

#### `trim_end`

`update_only` `no_fail`

```python
trim_end(bin[, policy][, context])
```

Description: Removes trailing Unicode whitespace.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_trim_end`](https://aerospike.com/docs/develop/expressions/string#string_trim_end)

Examples: Strip trailing whitespace

A record stores an address a user typed into a form, in a String bin called `email`. Trimming only the end preserves any leading content.

Given `email = " ana@corp.io "`, calling `trim_end("email")` leaves the bin holding `" ana@corp.io"`. The two leading spaces remain. Use [`trim`](#trim) to strip both sides.

Modify operations do not return a value. To read the trimmed string, add a read operation for the same bin to the same `operate()` call.

---

Whitespace is the full Unicode set

`trim_end` strips every codepoint carrying the Unicode `White_Space` property, not only spaces and tabs. That includes the no-break space (U+00A0), the figure space (U+2007), and the narrow no-break space (U+202F), so text pasted from a web page or a word processor loses those too.

A value that is entirely whitespace becomes the empty string rather than staying unchanged.

Code sample: -   [Java SDK](#tab-panel-2848)
-   [Python SDK](#tab-panel-2849)
-   [Rust](#tab-panel-2850)
-   [C#](#tab-panel-2851)
-   [Go](#tab-panel-2852)
-   [Node.js](#tab-panel-2853)
-   [C](#tab-panel-2854)
-   [Java](#tab-panel-2855)
-   [Python](#tab-panel-2856)

```java
try (RecordStream rs = session.upsert(key)

    .bin("email").trimEnd()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("email").str_trim_end().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::trim_end(&StringPolicy::default(), "email")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.TrimEnd(StringPolicy.Default, "email"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrTrimEndOp(as.DefaultStringPolicy, "email"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.trimEnd('email')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_trim_end(&ops, "email", NULL, NULL);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.trimEnd(StringPolicy.Default, "email"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.trim_end("email")])
```

---

#### `trim_start`

`update_only` `no_fail`

```python
trim_start(bin[, policy][, context])
```

Description: Removes leading Unicode whitespace.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_trim_start`](https://aerospike.com/docs/develop/expressions/string#string_trim_start)

Examples: Strip leading whitespace

A record stores an address a user typed into a form, in a String bin called `email`. Trimming only the front preserves any trailing content.

Given `email = " ana@corp.io "`, calling `trim_start("email")` leaves the bin holding `"ana@corp.io "`. The two trailing spaces remain. Use [`trim`](#trim) to strip both sides.

Modify operations do not return a value. To read the trimmed string, add a read operation for the same bin to the same `operate()` call.

---

Whitespace is the full Unicode set

`trim_start` strips every codepoint carrying the Unicode `White_Space` property, not only spaces and tabs. That includes the no-break space (U+00A0), the figure space (U+2007), and the narrow no-break space (U+202F), so text pasted from a web page or a word processor loses those too.

A value that is entirely whitespace becomes the empty string rather than staying unchanged.

Code sample: -   [Java SDK](#tab-panel-2857)
-   [Python SDK](#tab-panel-2858)
-   [Rust](#tab-panel-2859)
-   [C#](#tab-panel-2860)
-   [Go](#tab-panel-2861)
-   [Node.js](#tab-panel-2862)
-   [C](#tab-panel-2863)
-   [Java](#tab-panel-2864)
-   [Python](#tab-panel-2865)

```java
try (RecordStream rs = session.upsert(key)

    .bin("email").trimStart()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("email").str_trim_start().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::trim_start(&StringPolicy::default(), "email")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.TrimStart(StringPolicy.Default, "email"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrTrimStartOp(as.DefaultStringPolicy, "email"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.trimStart('email')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_trim_start(&ops, "email", NULL, NULL);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.trimStart(StringPolicy.Default, "email"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.trim_start("email")])
```

---

#### `upper`

`update_only` `no_fail`

```python
upper(bin[, policy][, context])
```

Description: Converts the String bin to uppercase.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `policy` | `String policy` | 

String write flags for the operation. Optional, and defaults to none. See [Operation flags](https://aerospike.com/docs/develop/data-types/string/operations#operation-flags).

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `none`

Introduced: 8.2.0

Expression form: [`string_upper`](https://aerospike.com/docs/develop/expressions/string#string_upper)

Examples: Uppercase a value

A record stores a display name in a String bin called `name`. Given `name = "ana borg"`, calling `upper("name")` leaves the bin holding `"ANA BORG"`.

Code sample: -   [Java SDK](#tab-panel-2866)
-   [Python SDK](#tab-panel-2867)
-   [Rust](#tab-panel-2868)
-   [C#](#tab-panel-2869)
-   [Go](#tab-panel-2870)
-   [Node.js](#tab-panel-2871)
-   [C](#tab-panel-2872)
-   [Java](#tab-panel-2873)
-   [Python](#tab-panel-2874)

```java
try (RecordStream rs = session.upsert(key)

    .bin("name").upper()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
session.upsert(key).bin("name").str_upper().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

client.operate(&WritePolicy::default(), &key,

    &[str_op::upper(&StringPolicy::default(), "name")]).await?;
```

```csharp
client.Operate(null, key,

    StringOperation.Upper(StringPolicy.Default, "name"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrUpperOp(as.DefaultStringPolicy, "name"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

await client.operate(key, [strings.upper('name')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_upper(&ops, "name", NULL, NULL);

aerospike_key_operate(&as, &err, NULL, &key, &ops, NULL);

as_operations_destroy(&ops);
```

```java
client.operate(null, key,

    StringOperation.upper(StringPolicy.Default, "name"));
```

```python
from aerospike_helpers.operations import string_operations as so

client.operate(key, [so.upper("name")])
```

---

## Read operations

#### `b64_decode`

```python
b64_decode(bin[, context])
```

Description: Decodes a base64-encoded string bin into a Blob.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `blob`

Introduced: 8.2.0

Expression form: [`string_b64_decode`](https://aerospike.com/docs/develop/expressions/string#string_b64_decode)

Examples: Decode a stored payload

A record stores a base64 payload in a String bin called `payload`. Given `payload = "aGVsbG8="`, calling `b64_decode("payload")` returns a 5-byte Blob holding the bytes `hello`.

---

Accepted encoding

Requires standard base64 with padding. The URL-safe variant and any whitespace are rejected, including the line breaks that `base64` and `openssl base64` insert by default. All of these return `AS_ERR_OP_NOT_APPLICABLE` without distinguishing which. An empty string decodes to an empty blob.

Code sample: -   [Java SDK](#tab-panel-2875)
-   [Python SDK](#tab-panel-2876)
-   [Rust](#tab-panel-2877)
-   [C#](#tab-panel-2878)
-   [Go](#tab-panel-2879)
-   [Node.js](#tab-panel-2880)
-   [C](#tab-panel-2881)
-   [Java](#tab-panel-2882)
-   [Python](#tab-panel-2883)

```java
try (RecordStream rs = session.query(key)

    .bin("payload").b64Decode()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("payload").str_b64_decode().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::b64_decode("payload")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.B64Decode("payload"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrB64DecodeOp("payload"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.b64Decode('payload')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_b64_decode(&ops, "payload", NULL);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    as_bytes* value = as_record_get_bytes(rec, "payload");

    // value points into rec; copy it before the record is destroyed.

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.b64Decode("payload"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.base64_decode("payload")])
```

---

#### `byte_length`

```python
byte_length(bin[, context])
```

Description: Returns the number of UTF-8 bytes in the string bin.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `integer`

Introduced: 8.2.0

Expression form: [`string_byte_length`](https://aerospike.com/docs/develop/expressions/string#string_byte_length)

Examples: Measure the stored bytes

Given `email = "aná@corp.io"`, calling `byte_length("email")` returns `12`, while [`strlen`](#strlen) returns `11`. The accented character occupies two UTF-8 bytes and one codepoint.

Code sample: -   [Java SDK](#tab-panel-2884)
-   [Python SDK](#tab-panel-2885)
-   [Rust](#tab-panel-2886)
-   [C#](#tab-panel-2887)
-   [Go](#tab-panel-2888)
-   [Node.js](#tab-panel-2889)
-   [C](#tab-panel-2890)
-   [Java](#tab-panel-2891)
-   [Python](#tab-panel-2892)

```java
try (RecordStream rs = session.query(key)

    .bin("email").byteLength()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("email").str_byte_length().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::byte_length("email")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.ByteLength("email"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrByteLengthOp("email"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.byteLength('email')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_byte_length(&ops, "email", NULL);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    int64_t value = as_record_get_int64(rec, "email", 0);

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.byteLength("email"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.byte_length("email")])
```

---

#### `char_at`

```python
char_at(bin, index[, context])
```

Description: Returns the single-codepoint substring at `index`. Supports negative indexes.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `index` | `integer` | 

Codepoint index.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `string`

Introduced: 8.2.0

Expression form: [`string_char_at`](https://aerospike.com/docs/develop/expressions/string#string_char_at)

Examples: Read a character by position

A record stores a contact address in a String bin called `email`. Reading a single character avoids transferring the whole value when only one position matters, such as bucketing addresses by their first letter.

Given `email = "ana@corp.io"`, calling `char_at("email", 0)` returns `"a"`. A negative index counts from the end, so `char_at("email", -1)` returns the last codepoint, `"o"`.

---

An out-of-range index does not fail

The index is clamped to `[0, length]` rather than rejected, and the two directions clamp to different results. `"ana@corp.io"` is 11 codepoints, so `char_at("email", 99)` clamps to the end and returns an empty string, while `char_at("email", -99)` clamps to `0` and returns the first codepoint, `"a"`.

Neither returns an error, and the underflow result is a valid codepoint that is indistinguishable from a deliberate `char_at("email", 0)`. Range-check the index before the operation when an out-of-range request must be told apart from a real character.

Code sample: -   [Java SDK](#tab-panel-2893)
-   [Python SDK](#tab-panel-2894)
-   [Rust](#tab-panel-2895)
-   [C#](#tab-panel-2896)
-   [Go](#tab-panel-2897)
-   [Node.js](#tab-panel-2898)
-   [C](#tab-panel-2899)
-   [Java](#tab-panel-2900)
-   [Python](#tab-panel-2901)

```java
try (RecordStream rs = session.query(key)

    .bin("email").charAt(0)

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("email").str_char_at(0).execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::char_at("email", 0)]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.CharAt("email", 0));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrCharAtOp("email", 0))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.charAt('email', 0)])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_char_at(&ops, "email", NULL, 0);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    char* value = as_record_get_str(rec, "email");

    // value points into rec; copy it before the record is destroyed.

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.charAt("email", 0));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.char_at("email", 0)])
```

---

#### `contains`

```python
contains(bin, needle[, context])
```

Description: Returns whether the string bin contains `needle`, respecting Unicode canonical equivalence.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `needle` | `string` | 

Substring to search for.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `boolean`

Introduced: 8.2.0

Expression form: [`string_contains`](https://aerospike.com/docs/develop/expressions/string#string_contains)

Examples: Test for a substring

Given `email = "ana@company.com"`, calling `contains("email", "@company.com")` returns `true`. Matching is anywhere in the value, not anchored to either end.

Code sample: -   [Java SDK](#tab-panel-2902)
-   [Python SDK](#tab-panel-2903)
-   [Rust](#tab-panel-2904)
-   [C#](#tab-panel-2905)
-   [Go](#tab-panel-2906)
-   [Node.js](#tab-panel-2907)
-   [C](#tab-panel-2908)
-   [Java](#tab-panel-2909)
-   [Python](#tab-panel-2910)

```java
try (RecordStream rs = session.query(key)

    .bin("email").contains("@company.com")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("email").str_contains("@company.com").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::contains("email", "@company.com")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.Contains("email", "@company.com"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrContainsOp("email", "@company.com"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [

    strings.contains('email', '@company.com')

])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_contains(&ops, "email", NULL, "@company.com");

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    bool value = as_record_get_bool(rec, "email");

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.contains("email", "@company.com"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.contains("email", "@company.com")])
```

---

#### `ends_with`

```python
ends_with(bin, suffix[, context])
```

Description: Returns whether the string bin ends with `suffix`. Treats canonically equivalent text as equal.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `suffix` | `string` | 

Suffix to test.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `boolean`

Introduced: 8.2.0

Expression form: [`string_ends_with`](https://aerospike.com/docs/develop/expressions/string#string_ends_with)

Examples: Test a suffix

Given `email = "ana@corp.com"`, calling `ends_with("email", ".com")` returns `true`, and `ends_with("email", ".org")` returns `false`.

Code sample: -   [Java SDK](#tab-panel-2911)
-   [Python SDK](#tab-panel-2912)
-   [Rust](#tab-panel-2913)
-   [C#](#tab-panel-2914)
-   [Go](#tab-panel-2915)
-   [Node.js](#tab-panel-2916)
-   [C](#tab-panel-2917)
-   [Java](#tab-panel-2918)
-   [Python](#tab-panel-2919)

```java
try (RecordStream rs = session.query(key)

    .bin("email").endsWith(".com")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("email").str_ends_with(".com").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::ends_with("email", ".com")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.EndsWith("email", ".com"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrEndsWithOp("email", ".com"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [

    strings.endsWith('email', '.com')

])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_ends_with(&ops, "email", NULL, ".com");

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    bool value = as_record_get_bool(rec, "email");

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.endsWith("email", ".com"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.ends_with("email", ".com")])
```

---

#### `find`

```python
find(bin, needle[, occurrence][, context])
```

Description: Returns the codepoint index of the `occurrence`th match of `needle`, or `-1` if not found. Treats canonically equivalent text as equal.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `needle` | `string` | 

Substring to find.

 |
| `occurrence` | `integer` | 

Match number, 1-based. Negative values count matches from the end (`-1` is the last match). Matches do not overlap. Must be non-zero: `0` returns `AS_ERR_PARAMETER`. Optional, and defaults to `1` (first match). Clients expose the two-argument form as `find` and the three-argument form as `find_occurrence` in C, and as a defaulted parameter in Java and Python.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `integer`

Introduced: 8.2.0

Expression form: [`string_find`](https://aerospike.com/docs/develop/expressions/string#string_find)

Examples: Locate a separator

A record stores a contact address in a String bin called `email`. Finding the separator lets an application split the local part from the domain without transferring the whole value.

Given `email = "ana@corp.co.uk"`, calling `find("email", "@")` returns `3`, the codepoint index of the match. An `occurrence` selects among repeats: `find("email", ".")` returns `8` for the first dot, and `find("email", ".", -1)` returns `11` for the last.

---

Matches do not overlap

Each match resumes after the previous one. On `"aaaa"` with needle `"aa"`, occurrence `1` returns `0`, `2` returns `2`, and `3` returns `-1`, even though `"aa"` begins at index 0, 1, and 2. Counting matches by walking `occurrence` upward undercounts a needle that can overlap itself.

Code sample: -   [Java SDK](#tab-panel-2920)
-   [Python SDK](#tab-panel-2921)
-   [Rust](#tab-panel-2922)
-   [C#](#tab-panel-2923)
-   [Go](#tab-panel-2924)
-   [Node.js](#tab-panel-2925)
-   [C](#tab-panel-2926)
-   [Java](#tab-panel-2927)
-   [Python](#tab-panel-2928)

```java
try (RecordStream rs = session.query(key)

    .bin("email").find("@")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("email").str_find("@").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::find("email", "@")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.Find("email", "@"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrFindOp("email", "@"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.find('email', '@')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_find(&ops, "email", NULL, "@");

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    int64_t value = as_record_get_int64(rec, "email", 0);

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.find("email", "@"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.find("email", "@")])
```

---

#### `is_lower`

```python
is_lower(bin[, context])
```

Description: Returns whether the string bin is lowercase: it holds no uppercase letter and at least one lowercase letter. Digits, spaces, and punctuation are ignored rather than counted against the value. An empty string returns `true`.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `boolean`

Introduced: 8.2.0

Expression form: [`string_is_lower`](https://aerospike.com/docs/develop/expressions/string#string_is_lower)

Examples: Test whether a value is lowercase

A record stores a short identifier in a String bin called `code`. Given `code = "hello"`, calling `is_lower("code")` returns `true`. A single uppercase letter fails the test, so `"Hello"` returns `false`.

Digits, spaces, and punctuation do not count against the value: `"hello world"`, `"abc123"`, and `"usd$"` all return `true`.

---

A value with no cased letter

A non-empty value holding no cased letter returns `false`, so `"123"`, `" "`, and `"42.5"` are all `false`. Use [`is_numeric`](https://aerospike.com/docs/develop/data-types/string/operations#is_numeric) to test for a numeric value.

The empty string is the exception, and returns `true`.

Code sample: -   [Java SDK](#tab-panel-2929)
-   [Python SDK](#tab-panel-2930)
-   [Rust](#tab-panel-2931)
-   [C#](#tab-panel-2932)
-   [Go](#tab-panel-2933)
-   [Node.js](#tab-panel-2934)
-   [C](#tab-panel-2935)
-   [Java](#tab-panel-2936)
-   [Python](#tab-panel-2937)

```java
try (RecordStream rs = session.query(key)

    .bin("code").isLower()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("code").str_is_lower().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::is_lower("code")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.IsLower("code"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrIsLowerOp("code"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.isLower('code')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_is_lower(&ops, "code", NULL);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    bool value = as_record_get_bool(rec, "code");

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.isLower("code"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.is_lower("code")])
```

---

#### `is_numeric`

```python
is_numeric(bin[, numeric_type][, context])
```

Description: Returns whether the string bin belongs to the requested numeric class.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `numeric_type` | `integer` | 

Numeric class to test for: `0` = ANY (int-class or float-class, the default), `1` = INT (optional sign then digits only, must fit `int64`), `2` = FLOAT (must contain a literal `.` followed by at least one digit, and must fit `double`). The values are mutually exclusive selectors, not combinable bits; any other value returns `AS_ERR_PARAMETER`. Optional; defaults to ANY. Constants are `NumericType` in Python, `StringNumericType` in Java, and `as_string_numeric_type` in C.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `boolean`

Introduced: 8.2.0

Expression form: [`string_is_numeric`](https://aerospike.com/docs/develop/expressions/string#string_is_numeric)

Examples: Test whether a value parses as a number

Given `amount = "42"`, calling `is_numeric("amount")` returns `true`. Given `amount = "42abc"`, it returns `false`. The default class accepts both integer and float forms.

---

Scientific notation

Float-class matching requires a literal `.` followed by a digit, so scientific-notation literals such as `1e5` match none of the three classes, including ANY. Do not use `is_numeric` to guard a [`to_double`](https://aerospike.com/docs/develop/data-types/string/operations#to_double) call: `to_double` parses scientific notation that `is_numeric` rejects.

Code sample: -   [Java SDK](#tab-panel-2938)
-   [Python SDK](#tab-panel-2939)
-   [Rust](#tab-panel-2940)
-   [C#](#tab-panel-2941)
-   [Go](#tab-panel-2942)
-   [Node.js](#tab-panel-2943)
-   [C](#tab-panel-2944)
-   [Java](#tab-panel-2945)
-   [Python](#tab-panel-2946)

```java
try (RecordStream rs = session.query(key)

    .bin("amount").isNumeric()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("amount").str_is_numeric().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::is_numeric("amount")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.IsNumeric("amount"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrIsNumericOp("amount"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.isNumeric('amount')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_is_numeric_type(&ops, "amount", NULL, AS_STRING_NUMERIC_ANY);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    bool value = as_record_get_bool(rec, "amount");

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.isNumeric("amount", StringNumericType.ANY));
```

```python
from aerospike_helpers.operations import string_operations as so

from aerospike_helpers.string_helpers import NumericType

_, _, bins = client.operate(key, [so.is_numeric("amount", NumericType.ANY)])
```

---

#### `is_upper`

```python
is_upper(bin[, context])
```

Description: Returns whether the string bin is uppercase: it holds no lowercase letter and at least one uppercase letter. Digits, spaces, and punctuation are ignored rather than counted against the value. An empty string returns `true`.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `boolean`

Introduced: 8.2.0

Expression form: [`string_is_upper`](https://aerospike.com/docs/develop/expressions/string#string_is_upper)

Examples: Test whether a value is uppercase

A record stores a short identifier in a String bin called `code`. Given `code = "HELLO"`, calling `is_upper("code")` returns `true`. A single lowercase letter fails the test, so `"Hello"` returns `false`.

Digits, spaces, and punctuation do not count against the value: `"HELLO WORLD"`, `"ABC123"`, and `"USD$"` all return `true`.

---

A value with no cased letter

A non-empty value holding no cased letter returns `false`, so `"123"`, `" "`, and `"42.5"` are all `false`. Use [`is_numeric`](https://aerospike.com/docs/develop/data-types/string/operations#is_numeric) to test for a numeric value.

The empty string is the exception, and returns `true`.

Code sample: -   [Java SDK](#tab-panel-2947)
-   [Python SDK](#tab-panel-2948)
-   [Rust](#tab-panel-2949)
-   [C#](#tab-panel-2950)
-   [Go](#tab-panel-2951)
-   [Node.js](#tab-panel-2952)
-   [C](#tab-panel-2953)
-   [Java](#tab-panel-2954)
-   [Python](#tab-panel-2955)

```java
try (RecordStream rs = session.query(key)

    .bin("code").isUpper()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("code").str_is_upper().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::is_upper("code")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.IsUpper("code"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrIsUpperOp("code"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.isUpper('code')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_is_upper(&ops, "code", NULL);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    bool value = as_record_get_bool(rec, "code");

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.isUpper("code"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.is_upper("code")])
```

---

#### `regex_compare`

```python
regex_compare(bin, pattern[, regex_flags][, context])
```

Description: Returns whether the string bin matches `pattern`, using ICU regular expression syntax.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `pattern` | `string` | 

Regular expression pattern, in ICU syntax. For the constructs ICU accepts, the ones it reads differently from PCRE, and the spellings it rejects at parse time, see [Regular expression syntax](https://aerospike.com/docs/develop/data-types/string/regex-syntax).

 |
| `regex_flags` | `integer` | 

Bit field of regex regex\_flags, combinable with bitwise OR. Optional, and defaults to `0` (no regex\_flags). `GLOBAL` is not valid here. For the values, their effects, and how AEL spells them, see [Regex flags](https://aerospike.com/docs/develop/data-types/string/regex-syntax#flags). Clients expose the two-argument form as `regex_compare` and the three-argument form as `regex_compare_flags` in C.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `boolean`

Introduced: 8.2.0

Expression form: [`string_regex_compare`](https://aerospike.com/docs/develop/expressions/string#string_regex_compare)

Examples: Match against a pattern

Given `email = "ana@company.com"`, calling `regex_compare("email", "^[^@]+@company\\.com$")` returns `true`. The pattern uses ICU syntax, and matches only where the pattern anchors it.

Code sample: -   [Java SDK](#tab-panel-2956)
-   [Python SDK](#tab-panel-2957)
-   [Rust](#tab-panel-2958)
-   [C#](#tab-panel-2959)
-   [Go](#tab-panel-2960)
-   [Node.js](#tab-panel-2961)
-   [C](#tab-panel-2962)
-   [Java](#tab-panel-2963)
-   [Python](#tab-panel-2964)

```java
try (RecordStream rs = session.query(key)

    .bin("email").regexCompare("^[^@]+@company\\.com$")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("email").str_regex_compare(r"^[^@]+@company\.com$").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::regex_compare("email", r"^[^@]+@company\.com$")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.RegexCompare("email", @"^[^@]+@company\.com$"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrRegexCompareOp("email", `^[^@]+@company\.com$`))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [

    strings.regexCompare('email', '^[^@]+@company\\.com$')

])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_regex_compare_flags(&ops, "email", NULL, "^[^@]+@company\\.com$",

    AS_STRING_REGEX_FLAGS_NONE);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    bool value = as_record_get_bool(rec, "email");

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.regexCompare("email", "^[^@]+@company\\.com$",

        StringRegexFlags.DEFAULT));
```

```python
from aerospike_helpers.operations import string_operations as so

from aerospike_helpers.string_helpers import RegexFlags

_, _, bins = client.operate(key, [so.regex_compare("email", r"^[^@]+@company\.com$", RegexFlags.DEFAULT)])
```

---

#### `split`

```python
split(bin[, separator][, context])
```

Description: Splits the string bin into a list of strings by `separator`.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `separator` | `string` | 

Delimiter string. Optional. When omitted, the bin is split into one list element per Unicode codepoint. Clients expose the no-separator form as `split` and the separator form as `split_separator` in Python and C, and as an overload of `split` in Java.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `list`

Introduced: 8.2.0

Expression form: [`string_split`](https://aerospike.com/docs/develop/expressions/string#string_split)

Examples: Split on a delimiter

A record stores a comma-separated label list in a String bin called `tags`. Splitting it server-side returns the parts as a List without the client parsing the value.

Given `tags = "red,green,blue"`, calling `split("tags", ",")` returns `["red", "green", "blue"]`.

---

Empty elements and empty bins

Every separator in the value produces a boundary, so adjacent, leading, and trailing separators yield empty elements rather than being collapsed. A separator that does not occur is not an error. The two empty-bin results differ depending on whether a separator was passed.

| Bin value | Call | Result |
| :-- | :-- | :-- |
| `"a,,b"` | `split("tags", ",")` | `["a", "", "b"]` |
| `",a"` | `split("tags", ",")` | `["", "a"]` |
| `"a,"` | `split("tags", ",")` | `["a", ""]` |
| `"abc"` | `split("tags", ",")` | `["abc"]` |
| `""` | `split("tags", ",")` | `[""]` |
| `""` | `split("tags")` | `[]` |
| `"abc"` | `split("tags")` | `["a", "b", "c"]` |

The last row is the one to watch. Omitting `separator` does not return the value unsplit: it returns one element per codepoint. Filtering empty elements out is the caller’s job; `split` does not do it.

Code sample: -   [Java SDK](#tab-panel-2965)
-   [Python SDK](#tab-panel-2966)
-   [Rust](#tab-panel-2967)
-   [C#](#tab-panel-2968)
-   [Go](#tab-panel-2969)
-   [Node.js](#tab-panel-2970)
-   [C](#tab-panel-2971)
-   [Java](#tab-panel-2972)
-   [Python](#tab-panel-2973)

```java
try (RecordStream rs = session.query(key)

    .bin("tags").split(",")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("tags").str_split(",").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::split_by_separator("tags", ",")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.Split("tags", ","));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrSplitBySeparatorOp("tags", ","))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [

    strings.splitSeparator('tags', ',')

])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_split_separator(&ops, "tags", NULL, ",");

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    as_list* value = as_record_get_list(rec, "tags");

    // value points into rec; copy it before the record is destroyed.

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.split("tags", ","));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.split_separator("tags", ",")])
```

---

#### `starts_with`

```python
starts_with(bin, prefix[, context])
```

Description: Returns whether the string bin starts with `prefix`. Treats canonically equivalent text as equal.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `prefix` | `string` | 

Prefix to test.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `boolean`

Introduced: 8.2.0

Expression form: [`string_starts_with`](https://aerospike.com/docs/develop/expressions/string#string_starts_with)

Examples: Test a prefix

Given `email = "user@corp.io"`, calling `starts_with("email", "user")` returns `true`, and `starts_with("email", "corp")` returns `false`.

Code sample: -   [Java SDK](#tab-panel-2974)
-   [Python SDK](#tab-panel-2975)
-   [Rust](#tab-panel-2976)
-   [C#](#tab-panel-2977)
-   [Go](#tab-panel-2978)
-   [Node.js](#tab-panel-2979)
-   [C](#tab-panel-2980)
-   [Java](#tab-panel-2981)
-   [Python](#tab-panel-2982)

```java
try (RecordStream rs = session.query(key)

    .bin("email").startsWith("user")

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("email").str_starts_with("user").execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::starts_with("email", "user")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.StartsWith("email", "user"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrStartsWithOp("email", "user"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [

    strings.startsWith('email', 'user')

])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_starts_with(&ops, "email", NULL, "user");

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    bool value = as_record_get_bool(rec, "email");

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.startsWith("email", "user"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.starts_with("email", "user")])
```

---

#### `strlen`

```python
strlen(bin[, context])
```

Description: Returns the number of Unicode codepoints in the string bin.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `integer`

Introduced: 8.2.0

Expression form: [`string_strlen`](https://aerospike.com/docs/develop/expressions/string#string_strlen)

Examples: Count codepoints

Given `email = "aná@corp.io"`, calling `strlen("email")` returns `11`, while [`byte_length`](#byte_length) returns `12`. The accented character is one codepoint and two UTF-8 bytes.

Code sample: -   [Java SDK](#tab-panel-2983)
-   [Python SDK](#tab-panel-2984)
-   [Rust](#tab-panel-2985)
-   [C#](#tab-panel-2986)
-   [Go](#tab-panel-2987)
-   [Node.js](#tab-panel-2988)
-   [C](#tab-panel-2989)
-   [Java](#tab-panel-2990)
-   [Python](#tab-panel-2991)

```java
try (RecordStream rs = session.query(key)

    .bin("email").strlen()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("email").str_strlen().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::strlen("email")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.Strlen("email"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrLenOp("email"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.strlen('email')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_strlen(&ops, "email", NULL);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    int64_t value = as_record_get_int64(rec, "email", 0);

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.strlen("email"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.strlen("email")])
```

---

#### `substr`

```python
substr(bin, from[, to][, context])
```

Description: Returns a substring by codepoint index. `from` is inclusive; `to` is exclusive. Supports negative indexes.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `from` | `integer` | 

Start codepoint index (inclusive).

 |
| `to` | `integer` | 

End codepoint index (exclusive). Optional, and defaults to the string’s codepoint length, returning the substring from `from` to the end of the string. Clients expose the two-argument form as `substr` and the three-argument form as `substr_range` in Python and C, and as an overload of `substr` in Java.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `string`

Introduced: 8.2.0

Expression form: [`string_substr`](https://aerospike.com/docs/develop/expressions/string#string_substr)

Examples: Extract a codepoint range

Given `email = "ana@corp.io"`, calling `substr("email", 0, 3)` returns `"ana"`. The range is half-open, so the codepoint at `to` is not included. Omitting `to` runs to the end of the string.

Code sample: -   [Java SDK](#tab-panel-2992)
-   [Python SDK](#tab-panel-2993)
-   [Rust](#tab-panel-2994)
-   [C#](#tab-panel-2995)
-   [Go](#tab-panel-2996)
-   [Node.js](#tab-panel-2997)
-   [C](#tab-panel-2998)
-   [Java](#tab-panel-2999)
-   [Python](#tab-panel-3000)

```java
try (RecordStream rs = session.query(key)

    .bin("email").substr(0, 3)

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("email").str_substr(0, 3).execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::substr("email", 0, 3)]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.Substr("email", 0, 3));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrSubstrOp("email", 0, 3))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [

    strings.substrRange('email', 0, 3)

])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_substr_range(&ops, "email", NULL, 0, 3);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    char* value = as_record_get_str(rec, "email");

    // value points into rec; copy it before the record is destroyed.

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.substr("email", 0, 3));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.substr_range("email", 0, 3)])
```

---

#### `to_blob`

```python
to_blob(bin[, context])
```

Description: Returns the UTF-8 bytes of the string bin as a Blob.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `blob`

Introduced: 8.2.0

Expression form: [`string_to_blob`](https://aerospike.com/docs/develop/expressions/string#string_to_blob)

Examples: Reinterpret the value as bytes

Given `payload = "hi"`, calling `to_blob("payload")` returns a 2-byte Blob holding the UTF-8 bytes of the string. The stored value is unchanged.

Code sample: -   [Java SDK](#tab-panel-3001)
-   [Python SDK](#tab-panel-3002)
-   [Rust](#tab-panel-3003)
-   [C#](#tab-panel-3004)
-   [Go](#tab-panel-3005)
-   [Node.js](#tab-panel-3006)
-   [C](#tab-panel-3007)
-   [Java](#tab-panel-3008)
-   [Python](#tab-panel-3009)

```java
try (RecordStream rs = session.query(key)

    .bin("payload").stringToBlob()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("payload").str_to_blob().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::to_blob("payload")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.ToBlob("payload"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrToBlobOp("payload"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.toBlob('payload')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_to_blob(&ops, "payload", NULL);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    as_bytes* value = as_record_get_bytes(rec, "payload");

    // value points into rec; copy it before the record is destroyed.

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.toBlob("payload"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.to_blob("payload")])
```

---

#### `to_double`

```python
to_double(bin[, context])
```

Description: Parses the string bin as a float. Accepts decimal digits, exponent form, and the `inf` and `nan` literals.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `float`

Introduced: 8.2.0

Expression form: [`string_to_double`](https://aerospike.com/docs/develop/expressions/string#string_to_double)

Examples: Parse the value as a float

Given `rate = "1.5"`, calling `to_double("rate")` returns `1.5`. Exponent form such as `1.5e10` parses too.

---

Accepted grammar

An optional sign followed by decimal digits, with an optional fractional part and an optional exponent: `-1.5`, `1.5e10`, `2E-3`. The case-insensitive literals `inf`, `infinity`, and `nan` are accepted, with an optional sign, so every value [`to_string`](https://aerospike.com/docs/develop/data-types/string/operations#to_string) emits for a float parses back.

Those three succeed and return a non-finite float rather than an error, so a bin holding the word `nan` converts rather than failing. Summing or averaging `to_double` over a text column poisons the whole aggregate from one such row. Filter the rows or check each value before aggregating.

These forms are rejected, though some languages’ own float parsers accept them: leading whitespace (`" 42"`), hexadecimal (`0x10`, `0x1p3`), a `.` with no digit after it (`5.`, `5.e3`), and `nan` payloads (`nan(0x1)`). Trailing characters are rejected too, so `12abc` does not parse as `12`.

---

Parse failures

A string that is not a valid float, or whose value does not fit in `double`, returns `AS_ERR_OP_NOT_APPLICABLE` with subcode `AS_SUB_OPNOT_STRING_CONVERSION_FAILED`. It does not return `AS_ERR_PARAMETER`, which is reserved for a malformed operation rather than unparseable data. Branch on `AS_ERR_OP_NOT_APPLICABLE` to catch failed conversions.

`to_double` accepts exponent form such as `1e5`, and the `inf` and `nan` literals, all of which [`is_numeric`](https://aerospike.com/docs/develop/data-types/string/operations#is_numeric) rejects, so `is_numeric` is not a valid guard for this operation.

A string longer than 327 characters is rejected on length alone, before any parsing. That is the longest decimal form a `double` can take, which the smallest values need when written out in full.

Code sample: -   [Java SDK](#tab-panel-3010)
-   [Python SDK](#tab-panel-3011)
-   [Rust](#tab-panel-3012)
-   [C#](#tab-panel-3013)
-   [Go](#tab-panel-3014)
-   [Node.js](#tab-panel-3015)
-   [C](#tab-panel-3016)
-   [Java](#tab-panel-3017)
-   [Python](#tab-panel-3018)

```java
try (RecordStream rs = session.query(key)

    .bin("rate").stringToDouble()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("rate").str_to_double().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::to_double("rate")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.ToDouble("rate"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrToDoubleOp("rate"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.toDouble('rate')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_to_double(&ops, "rate", NULL);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    double value = as_record_get_double(rec, "rate", 0.0);

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.toDouble("rate"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.to_double("rate")])
```

---

#### `to_integer`

```python
to_integer(bin[, context])
```

Description: Parses the string bin as a signed integer.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |
| `context` | `Context instance` | 

Optional [context path](https://aerospike.com/docs/develop/data-types/collections/context) from the bin to a string nested inside a List or Map, one selector per nesting level. Omit it when the bin holds the string itself.

 |

Returns: `integer`

Introduced: 8.2.0

Expression form: [`string_to_integer`](https://aerospike.com/docs/develop/expressions/string#string_to_integer)

Examples: Parse the value as an integer

Given `count = "42"`, calling `to_integer("count")` returns `42`. A value that does not parse, or does not fit in `int64`, returns an error rather than a partial result.

---

Parse failures

A string that is not a valid integer, or whose value does not fit in `int64`, returns `AS_ERR_OP_NOT_APPLICABLE` with subcode `AS_SUB_OPNOT_STRING_CONVERSION_FAILED`. It does not return `AS_ERR_PARAMETER`, which is reserved for a malformed operation rather than unparseable data. Branch on `AS_ERR_OP_NOT_APPLICABLE` to catch failed conversions.

A string longer than 20 characters is rejected on length alone, before any parsing. Twenty characters is the longest valid `int64`, `-9223372036854775808`, so nothing longer can be in range.

Code sample: -   [Java SDK](#tab-panel-3019)
-   [Python SDK](#tab-panel-3020)
-   [Rust](#tab-panel-3021)
-   [C#](#tab-panel-3022)
-   [Go](#tab-panel-3023)
-   [Node.js](#tab-panel-3024)
-   [C](#tab-panel-3025)
-   [Java](#tab-panel-3026)
-   [Python](#tab-panel-3027)

```java
try (RecordStream rs = session.query(key)

    .bin("count").stringToInteger()

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("count").str_to_integer().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::to_integer("count")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.ToInteger("count"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrToIntegerOp("count"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.toInteger('count')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_string_to_integer(&ops, "count", NULL);

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    int64_t value = as_record_get_int64(rec, "count", 0);

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.toInteger("count"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.to_integer("count")])
```

---

## Type conversion

#### `to_string`

```python
to_string(bin)
```

Description: Converts an integer, float, boolean, blob, or string bin to its string representation.

Arguments: | Name | Type | Description |
| --- | --- | --- |
| `bin` | `string` | 
Name of bin.

 |

Returns: `string`

Introduced: 8.2.0

Expression form: [`to_string`](https://aerospike.com/docs/develop/expressions/string#to_string)

Examples: Convert a bin without knowing its type

A record stores a counter in a bin called `score`, and the caller does not know the bin’s type in advance. Given `score = 42`, calling `to_string("score")` returns `"42"`.

---

Result by source type

| Bin type | Result |
| :-- | :-- |
| Integer | Exact decimal. |
| Float | Six significant digits, in exponent form outside `[1e-5, 1e6)`. `3.141592653589793` becomes `"3.14159"`, and `1234567.0` becomes `"1.23457e+06"`. |
| Boolean | `"true"` or `"false"`. |
| Blob | The stored bytes as they are, not base64 or hex. A blob holding invalid UTF-8 returns `AS_ERR_OP_NOT_APPLICABLE`. |
| String | Unchanged. |

---

Conversions that lose data or fail

Float is the one supported type that loses information. `to_string` followed by [`to_double`](#to_double) does not round-trip a float: `1234567.0` returns as `1234570.0`. Convert on the client when the exact value matters.

List, Map, GeoJSON, and HLL bins are not supported at all and return `AS_ERR_INCOMPATIBLE_TYPE`.

Code sample: -   [Java SDK](#tab-panel-3028)
-   [Python SDK](#tab-panel-3029)
-   [Rust](#tab-panel-3030)
-   [C#](#tab-panel-3031)
-   [Go](#tab-panel-3032)
-   [Node.js](#tab-panel-3033)
-   [C](#tab-panel-3034)
-   [Java](#tab-panel-3035)
-   [Python](#tab-panel-3036)

```java
try (RecordStream rs = session.query(key)

    .appendOperations(StringOperation.toString("score"))

    .execute()) {

    Record rec = rs.next().recordOrThrow();

}
```

```python
stream = session.query(key).bin("score").read_as_string().execute()
```

```rust
// Requires: use aerospike::operations::string as str_op;

let record = client.operate(&WritePolicy::default(), &key,

    &[str_op::to_string("score")]).await?;
```

```csharp
Record record = client.Operate(null, key,

    StringOperation.ToString("score"));
```

```go
// Requires: import as "github.com/aerospike/aerospike-client-go/v8"

client.Operate(nil, key,

    as.StrToStringOp("score"))
```

```javascript
const Aerospike = require('aerospike')

const strings = Aerospike.strings

const record = await client.operate(key, [strings.toString('score')])
```

```c
as_operations ops;

as_operations_init(&ops, 1);

as_operations_to_string(&ops, "score");

as_record* rec = NULL;

if (aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec) == AEROSPIKE_OK) {

    char* value = as_record_get_str(rec, "score");

    // value points into rec; copy it before the record is destroyed.

    as_record_destroy(rec);

}

as_operations_destroy(&ops);
```

```java
Record record = client.operate(null, key,

    StringOperation.toString("score"));
```

```python
from aerospike_helpers.operations import string_operations as so

_, _, bins = client.operate(key, [so.to_string("score")])
```

---