Skip to main content

String Built-ins

FunctionDescriptionOPAWasmSwiftJava
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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.0SDK0.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.0SDK0.0.10.1.0
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

v0.17.00.0.10.1.0
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.0SDK0.0.50.1.0
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.0SDK0.0.50.1.0
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.0SDK0.0.10.1.0
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.0SDK0.0.5
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

v0.17.00.0.50.1.0
strings.reverse

y := strings.reverse(x)

Reverses a given string.

Arguments:
x (string)

string to reverse

Returns:
y (string)

reversed string

v0.36.00.0.10.1.0
strings.split_n

ys := strings.split_n(x, delimiter, n)

Returns an array of at most n parts of x split on delimiter. If n is positive, returns the first n parts. If n is negative, returns the last abs(n) parts. If n is zero, returns an empty array. If abs(n) exceeds the number of parts, all parts are returned.

Arguments:
x (string)

string that is split

delimiter (string)

delimiter used for splitting

n (number)

number of parts to return; positive selects from the left, negative from the right, zero returns an empty array

Returns:
ys (array[string])

split parts

v1.19.0SDK
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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

v0.17.00.0.10.1.0
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: Checks if a string starts with a specified prefix.
  • Any Prefix Match: Checks if a string starts with any of the specified prefixes.
  • Ends With: Checks if a string ends with a specified suffix.
  • Any 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.

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 play

example1 if contains("alice@example.com", "@")

example2 if contains("bob[at]example.com", "@")

example3 if contains(input.email, "@")
Output
{
  "example1": true
}
Loading...
input.json
{
"email": "hello at example.com"
}
data.json
{}

Open in OPA Playground

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 play

banned_words := {"hate", "kill"}

reasons contains word if {
some word in banned_words
contains(input.message, word)
}
Output
{
  "banned_words": [
    "hate",
    "kill"
  ],
  "reasons": [
    "hate"
  ]
}
Loading...
input.json
{
"message": "i hate bananas"
}
data.json
{}

Open in OPA Playground

startswith

startswith reports whether a string begins with a given prefix. Prefer it over contains when the match must be at the front of the value (HTTP paths, registry prefixes, file paths).

Restricting requests to an API path prefix

When a policy only cares about the start of a string — for example an HTTP path or a registry prefix — startswith is clearer (and usually safer) than a loose contains check.

This example allows only paths under /api/v1/.

policy.rego
package play

default allow := false

allow if startswith(input.path, "/api/v1/")

deny contains msg if {
not allow
msg := sprintf("path %q is outside /api/v1/", [input.path])
}
Output
{
  "allow": false,
  "deny": [
    "path \"/api/v2/users\" is outside /api/v1/"
  ]
}
Loading...
input.json
{
"path": "/api/v2/users"
}
data.json
{}

Open in OPA Playground

sprintf

sprintf builds a string from a format and a list of values. Deny rules use it to put the failing field and value into the message returned to the caller.

See also the note at the top of this page about how sprintf pre-processes values (for example with %T).

Building a clear deny message

sprintf formats a string with values from the policy. Admission and authorization policies use it so users see which field failed and what value was rejected, not only a bare false.

policy.rego
package play

# Guests may read, but nothing else.
deny contains msg if {
input.role == "guest"
input.action != "read"
msg := sprintf(
"user %v with role %v cannot %v %v",
[input.user, input.role, input.action, input.resource],
)
}
Output
{
  "deny": [
    "user alice with role guest cannot delete orders/42"
  ]
}
Loading...
input.json
{
"user": "alice",
"role": "guest",
"action": "delete",
"resource": "orders/42"
}
data.json
{}

Open in OPA Playground

split

split returns a list of substrings separated by a delimiter. Use it when a path, hostname, or other structured string needs to be broken into parts.

Pull a path segment with split

split breaks a string into a list of parts. Policies often use it to pull a segment out of a path or dotted name before comparing against a list of allowed values.

policy.rego
package play

# "/teams/payments/deploy" -> ["", "teams", "payments", "deploy"]
parts := split(input.path, "/")
team := parts[2]

default allow := false

allow if team == "payments"
Output
{
  "allow": true,
  "parts": [
    "",
    "teams",
    "payments",
    "deploy"
  ],
  "team": "payments"
}
Loading...
input.json
{
"path": "/teams/payments/deploy"
}
data.json
{}

Open in OPA Playground

lower

lower converts a string to lowercase. It is useful for normalisation and formatting when values may arrive in mixed case.

Normalize roles with lower

lower returns the lowercase form of a string. Use it when identity providers send mixed-case roles or emails and you want a stable comparison.

policy.rego
package play

role := lower(input.role)

default allow := false

allow if role in data.admin_roles
Output
{
  "allow": true,
  "role": "admin"
}
Loading...
input.json
{
"role": "Admin"
}
data.json
{
"admin_roles": [
"admin",
"owner"
]
}

Open in OPA Playground

endswith

endswith reports whether a string ends with a given suffix. Use this function to valid matches at the ends of string values (file extensions, email domains, path suffixes etc.).

Allow only approved file extensions

endswith checks whether a string ends with a given suffix. Use it for file extensions, email domains, or other trailing markers where contains would match in the wrong place.

This example denies filenames that do not end with .json or .yaml.

policy.rego
package play

deny contains $"disallowed ext: {input.filename}" if {
not _valid_file_ext
}

_valid_file_ext if endswith(input.filename, ".json")
_valid_file_ext if endswith(input.filename, ".yaml")
Output
{
  "deny": [
    "disallowed ext: report.exe"
  ]
}
Loading...
input.json
{
"filename": "report.exe"
}
data.json
{}

Open in OPA Playground

replace

replace returns a string with every occurrence of a substring swapped for another. A common policy use is redacting sensitive values.

Redact a confidential header from a user-facing message

When a policy builds a user-facing error, it can accidentally include a sensitive header value. replace redacts that substring before the message goes back to the caller.

policy.rego
package play

# Message that would leak a confidential header, then redacted for the caller.
safe_message := replace(
sprintf("upstream rejected request with %s", [input.headers.authorization]),
input.headers.authorization,
"[REDACTED]",
)
Output
{
  "safe_message": "upstream rejected request with [REDACTED]"
}
Loading...
input.json
{
"headers": {
"authorization": "Bearer abc123xyz"
}
}
data.json
{}

Open in OPA Playground