# String Built-ins

| Function | Description | Meta |
| --- | --- | --- |
| `concat` | `output := concat(delimiter, collection)`  Joins a set or array of strings with a delimiter.  **Arguments:**  `delimiter` (string)  string to use as a delimiter  `collection` (any<array\[string\], set\[string\]>)  strings to join  **Returns:**  `output` (string)  the joined string | Wasm |
| `contains` | `result := contains(haystack, needle)`  Returns `true` if the search string is included in the base string  **Arguments:**  `haystack` (string)  string to search in  `needle` (string)  substring to look for  **Returns:**  `result` (boolean)  result of the containment check | Wasm |
| `endswith` | `result := endswith(search, base)`  Returns true if the search string ends with the base string.  **Arguments:**  `search` (string)  search string  `base` (string)  base string  **Returns:**  `result` (boolean)  result of the suffix check | Wasm |
| `format_int` | `output := format_int(number, base)`  Returns the string representation of the number in the given base after rounding it down to an integer value.  **Arguments:**  `number` (number)  number to format  `base` (number)  base of number representation to use  **Returns:**  `output` (string)  formatted number | Wasm |
| `indexof` | `output := indexof(haystack, needle)`  Returns the index of a substring contained inside a string.  **Arguments:**  `haystack` (string)  string to search in  `needle` (string)  substring to look for  **Returns:**  `output` (number)  index of first occurrence, `-1` if not found | Wasm |
| `indexof_n` | `output := indexof_n(haystack, needle)`  Returns a list of all the indexes of a substring contained inside a string.  **Arguments:**  `haystack` (string)  string to search in  `needle` (string)  substring to look for  **Returns:**  `output` (array\[number\])  all indices at which `needle` occurs in `haystack`, may be empty | [v0.37.0](https://github.com/open-policy-agent/opa/releases/v0.37.0) SDK-dependent |
| `lower` | `y := lower(x)`  Returns the input string but with all characters in lower-case.  **Arguments:**  `x` (string)  string that is converted to lower-case  **Returns:**  `y` (string)  lower-case of x | Wasm |
| `replace` | `y := replace(x, old, new)`  Replace replaces all instances of a sub-string.  **Arguments:**  `x` (string)  string being processed  `old` (string)  substring to replace  `new` (string)  string to replace `old` with  **Returns:**  `y` (string)  string with replaced substrings | Wasm |
| `split` | `ys := split(x, delimiter)`  Split returns an array containing elements of the input string split on a delimiter.  **Arguments:**  `x` (string)  string that is split  `delimiter` (string)  delimiter used for splitting  **Returns:**  `ys` (array\[string\])  split parts | Wasm |
| `sprintf` | `output := sprintf(format, values)`  Returns the given string, formatted.  **Arguments:**  `format` (string)  string with formatting verbs  `values` (array\[any\])  arguments to format into formatting verbs  **Returns:**  `output` (string)  `format` formatted by the values in `values` | SDK-dependent |
| `startswith` | `result := startswith(search, base)`  Returns true if the search string begins with the base string.  **Arguments:**  `search` (string)  search string  `base` (string)  base string  **Returns:**  `result` (boolean)  result of the prefix check | Wasm |
| `strings.any_prefix_match` | `result := strings.any_prefix_match(search, base)`  Returns true if any of the search strings begins with any of the base strings.  **Arguments:**  `search` (any<string, array\[string\], set\[string\]>)  search string(s)  `base` (any<string, array\[string\], set\[string\]>)  base string(s)  **Returns:**  `result` (boolean)  result of the prefix check | [v0.44.0](https://github.com/open-policy-agent/opa/releases/v0.44.0) SDK-dependent |
| `strings.any_suffix_match` | `result := strings.any_suffix_match(search, base)`  Returns true if any of the search strings ends with any of the base strings.  **Arguments:**  `search` (any<string, array\[string\], set\[string\]>)  search string(s)  `base` (any<string, array\[string\], set\[string\]>)  base string(s)  **Returns:**  `result` (boolean)  result of the suffix check | [v0.44.0](https://github.com/open-policy-agent/opa/releases/v0.44.0) SDK-dependent |
| `strings.count` | `output := strings.count(search, substring)`  Returns the number of non-overlapping instances of a substring in a string.  **Arguments:**  `search` (string)  string to search in  `substring` (string)  substring to look for  **Returns:**  `output` (number)  count of occurrences, `0` if not found | [v0.67.0](https://github.com/open-policy-agent/opa/releases/v0.67.0) SDK-dependent |
| `strings.render_template` | `result := strings.render_template(value, vars)`  Renders a templated string with given template variables injected. For a given templated string and key/value mapping, values will be injected into the template where they are referenced by key. For examples of templating syntax, see https://pkg.go.dev/text/template  **Arguments:**  `value` (string)  a templated string  `vars` (object\[string: any\])  a mapping of template variable keys to values  **Returns:**  `result` (string)  rendered template with template variables injected | [v0.59.0](https://github.com/open-policy-agent/opa/releases/v0.59.0) SDK-dependent |
| `strings.replace_n` | `output := strings.replace_n(patterns, value)`  Replaces a string from a list of old, new string pairs. Replacements are performed in the order they appear in the target string, without overlapping matches. The old string comparisons are done in argument order.  **Arguments:**  `patterns` (object\[string: string\])  replacement pairs  `value` (string)  string to replace substring matches in  **Returns:**  `output` (string)  string with replaced substrings | Wasm |
| `strings.reverse` | `y := strings.reverse(x)`  Reverses a given string.  **Arguments:**  `x` (string)  string to reverse  **Returns:**  `y` (string)  reversed string | [v0.36.0](https://github.com/open-policy-agent/opa/releases/v0.36.0) Wasm |
| `substring` | `output := substring(value, offset, length)`  Returns the portion of a string for a given `offset` and a `length`. If `length < 0`, `output` is the remainder of the string.  **Arguments:**  `value` (string)  string to extract substring from  `offset` (number)  offset, must be positive  `length` (number)  length of the substring starting from `offset`  **Returns:**  `output` (string)  substring of `value` from `offset`, of length `length` | Wasm |
| `trim` | `output := trim(value, cutset)`  Returns `value` with all leading or trailing instances of the `cutset` characters removed.  **Arguments:**  `value` (string)  string to trim  `cutset` (string)  string of characters that are cut off  **Returns:**  `output` (string)  string trimmed of `cutset` characters | Wasm |
| `trim_left` | `output := trim_left(value, cutset)`  Returns `value` with all leading instances of the `cutset` characters removed.  **Arguments:**  `value` (string)  string to trim  `cutset` (string)  string of characters that are cut off on the left  **Returns:**  `output` (string)  string left-trimmed of `cutset` characters | Wasm |
| `trim_prefix` | `output := trim_prefix(value, prefix)`  Returns `value` without the prefix. If `value` doesn't start with `prefix`, it is returned unchanged.  **Arguments:**  `value` (string)  string to trim  `prefix` (string)  prefix to cut off  **Returns:**  `output` (string)  string with `prefix` cut off | Wasm |
| `trim_right` | `output := trim_right(value, cutset)`  Returns `value` with all trailing instances of the `cutset` characters removed.  **Arguments:**  `value` (string)  string to trim  `cutset` (string)  string of characters that are cut off on the right  **Returns:**  `output` (string)  string right-trimmed of `cutset` characters | Wasm |
| `trim_space` | `output := trim_space(value)`  Return the given string with all leading and trailing white space removed.  **Arguments:**  `value` (string)  string to trim  **Returns:**  `output` (string)  string leading and trailing white space cut off | Wasm |
| `trim_suffix` | `output := trim_suffix(value, suffix)`  Returns `value` without the suffix. If `value` doesn't end with `suffix`, it is returned unchanged.  **Arguments:**  `value` (string)  string to trim  `suffix` (string)  suffix to cut off  **Returns:**  `output` (string)  string with `suffix` cut off | Wasm |
| `upper` | `y := upper(x)`  Returns the input string but with all characters in upper-case.  **Arguments:**  `x` (string)  string that is converted to upper-case  **Returns:**  `y` (string)  upper-case of x | Wasm |

info

When using `sprintf`, values are pre-processed and may have an unexpected type. For example, `%T` evaluates to `string` for both `string` and `boolean` types. In such cases, use `type_name` to accurately evaluate the underlying type.

## Examples

### `contains`

`contains` is a commonly used Rego built-in function that checks if a string contains a substring. The function returns `true` if the string contains the substring and `false` otherwise.

Some examples of policy use cases where `contains` might be used include:

*   Simple validation, such as checking if an email contains a `@` symbol.
*   Checking if user input contains restricted words or phrases for content moderation.

caution

If you're looking to check a string that's expected to be at the start or end of a value, you might be better served by one of the following functions:

*   [Starts With](#builtin-strings-startswith): Checks if a string starts with a specified prefix.
*   [Any Prefix Match](#builtin-strings-stringsany_prefix_match): Checks if a string starts with any of the specified prefixes.
*   [Ends With](#builtin-strings-endswith): Checks if a string ends with a specified suffix.
*   [Any Suffix Match](#builtin-strings-stringsany_suffix_match): Checks if a string ends with any of the specified suffixes.

These are safer and potentially faster too.

danger

`contains` only operates on strings, if you're looking to check for the presence of a value in a list you cannot use this function.

note

If you're looking for the Rego keyword `contains` for building multi-value rules, you can read about it in the [keywords section](/docs/policy-reference/keywords/contains).

Simple email validation

In the example that follows, `contains` is used to test if the `@` symbol is contained in the supplied email address. This can be useful as a first check on raw user data.

policy.rego

```
package playimport rego.v1example1 if contains("alice@example.com", "@")example2 if contains("bob[at]example.com", "@")example3 if contains(input.email, "@")
```

Output

{
  "example1": true
}

input.json

```
{  "email": "hello at example.com"}
```

data.json

```
{}
```

[Open in OPA Playground](https://play.openpolicyagent.org/?state=eyJpIjoie1xuICBcImVtYWlsXCI6IFwiaGVsbG8gYXQgZXhhbXBsZS5jb21cIlxufSIsImQiOiJ7fSIsInAiOiJwYWNrYWdlIHBsYXlcblxuaW1wb3J0IHJlZ28udjFcblxuZXhhbXBsZTEgaWYgY29udGFpbnMoXCJhbGljZUBleGFtcGxlLmNvbVwiLCBcIkBcIilcblxuZXhhbXBsZTIgaWYgY29udGFpbnMoXCJib2JbYXRdZXhhbXBsZS5jb21cIiwgXCJAXCIpXG5cbmV4YW1wbGUzIGlmIGNvbnRhaW5zKGlucHV0LmVtYWlsLCBcIkBcIilcbiJ9)

Keyword checking for content moderation

The `contains` function is also useful for checking user text for keywords, certain keywords might not be allowed. In this example, `reasons` will be a list of the banned words found in the `input.message`.

policy.rego

```
package playimport rego.v1banned_words := {"hate", "kill"}reasons contains word if {	some word in banned_words	contains(input.message, word)}
```

Output

{
  "banned\_words": \[
    "hate",
    "kill"
  \],
  "reasons": \[
    "hate"
  \]
}

input.json

```
{  "message": "i hate bananas"}
```

data.json

```
{}
```

[Open in OPA Playground](https://play.openpolicyagent.org/?state=eyJpIjoie1xuICBcIm1lc3NhZ2VcIjogXCJpIGhhdGUgYmFuYW5hc1wiXG59IiwiZCI6Int9IiwicCI6InBhY2thZ2UgcGxheVxuXG5pbXBvcnQgcmVnby52MVxuXG5iYW5uZWRfd29yZHMgOj0ge1wiaGF0ZVwiLCBcImtpbGxcIn1cblxucmVhc29ucyBjb250YWlucyB3b3JkIGlmIHtcblx0c29tZSB3b3JkIGluIGJhbm5lZF93b3Jkc1xuXHRjb250YWlucyhpbnB1dC5tZXNzYWdlLCB3b3JkKVxufVxuIn0=)