> For the complete documentation index, see [llms.txt](https://docs.ninox.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ninox.com/ninox-scripting/automate-your-workflows/work-with-functions/text-and-strings.md).

# Text and strings

Text values are at the heart of most Ninox apps. You use them for names and addresses, labels on buttons, messages in alerts, IDs and codes, and data exchanged with other systems. This chapter shows you how to build, clean, search, and format text so it looks right and works reliably in your logic, views, and integrations.

In this chapter, you will learn how to:

* Build and change text values for labels, messages, and IDs.
* Search, extract, and clean up parts of a string.
* Format numbers, dates, and times as readable text.
* Work with text formats like CSV, JSON, and XML for integrations.

<table><thead><tr><th width="149.2109375">Function (A-Z)</th><th>Task</th></tr></thead><tbody><tr><td><code>chosen()</code></td><td>Evaluate selected values in a multiple choice field</td></tr><tr><td><code>concat()</code></td><td>Return comma-separated text from a list of items</td></tr><tr><td><code>contains()</code></td><td>Check whether text or a list contains an exact value</td></tr><tr><td><code>eval()</code></td><td>Execute strings as Ninox functions, including table or field names</td></tr><tr><td><code>extractx()</code></td><td>Extract text with a regular expression</td></tr><tr><td><code>format()</code></td><td>Format numbers, dates, and times as text</td></tr><tr><td><code>formatJSON()</code></td><td>Convert a JSON object to text</td></tr><tr><td><code>formatXML()</code></td><td>Convert JSON to XML text</td></tr><tr><td><code>html()</code></td><td>Return a rich text representation of a value</td></tr><tr><td><code>icon()</code></td><td>Return an icon value</td></tr><tr><td><code>index()</code></td><td>Return the first matching position in text or arrays</td></tr><tr><td><code>join()</code></td><td>Return text from a list of items, separated by a custom character</td></tr><tr><td><code>length()</code></td><td>Measure the size of text or lists</td></tr><tr><td><code>lpad()</code></td><td>Pad text to a fixed length on the left</td></tr><tr><td><code>parseCSV()</code></td><td>Convert CSV text into rows and columns</td></tr><tr><td><code>parseJSON()</code></td><td>Convert a JSON string to a JSON object</td></tr><tr><td><code>parseXML()</code></td><td>Convert XML text to a JSON object</td></tr><tr><td><code>replace()</code></td><td>Replace one string with another</td></tr><tr><td><code>replacex()</code></td><td>Replace text using a regular expression</td></tr><tr><td><code>rpad()</code></td><td>Pad text to a fixed length on the right</td></tr><tr><td><code>split()</code></td><td>Split text into parts and provide an array</td></tr><tr><td><code>string()</code><br><code>text()</code></td><td>Convert values to plain text</td></tr><tr><td><code>styled()</code><br><code>color()</code><br><code>icon()</code><br><code>html()</code></td><td>Style text, return icon values, and render rich text</td></tr><tr><td><code>substr()</code><br><code>substring()</code></td><td>Extract part of a text</td></tr><tr><td><code>testx()</code></td><td>Check text against a regular expression</td></tr><tr><td><code>trim()</code></td><td>Remove extra spaces</td></tr><tr><td><code>upper()</code><br><code>lower()</code><br><code>capitalize()</code></td><td>Change the letter case of text</td></tr></tbody></table>

## Return values as comma-separated text <a href="#combine-pieces-of-text-into-one-line" id="combine-pieces-of-text-into-one-line"></a>

Use `concat()` to return values as one text string separated by commas. It works with arrays, table results, multiple-choice fields, and direct values.

Use it when you want to:

* Show selected options from a multiple-choice field as running text.
* Turn array or table values into text for a form or print layout.
* Store a comma-separated result in a text field or text variable.

`concat([any])`\
`concat(value1, value2, ...)`

* `[any]`: an array, table result, or multiple-choice field
* `value1, value2, ...`: individual values you want to return as one text string

#### Let’s take a look at some examples: <a href="#lets-take-a-look-at-some-examples" id="lets-take-a-look-at-some-examples"></a>

```
concat(select members.first_name)
```

Returns all values of the field "First name" from the table "Members" as one string, separated by a comma.\
The script returns, for example, "Max, Mary, Kim" if there are three linked records with content in the field "First name".\ <br>

```
concat(interests)
```

Returns all selected items from the multiple-choice field `interests` as one string.\
If the selected options are `Marketing`, `Sales`, and `Support`, the script returns `"Marketing, Sales, Support"`.

Tips:

* Use [`join()`](#combine-a-list-of-text-values-into-one-string) when you need a separator other than a comma.

## Evaluate selected values in multiple choice fields

Use `chosen()` when you want to read or check the selected values of a multiple choice field.

### Check or return selected values with `chosen()`

Use `chosen()` to return all selected options from a multiple choice field, or to check whether a specific value or ID is part of the selection.

Use it when you want to:

* Return the selected labels from a multiple choice field.
* Check whether one selected option is present.
* Check whether several selected option IDs are all present.
* Filter records where only one exact value is selected.

`chosen(multi)`\
`chosen(multi, string)`\
`chosen(multi, number)`\
`chosen(multi, [number])`<br>

* `multi`: a multiple choice field
* `string`: a selected label to check
* `number`: a selected option ID or record ID to check
* `[number]`: a list of selected option IDs or record IDs to check

`chosen()` returns either a boolean or an array of strings, depending on how you call it.

#### Let’s take a look at some examples:

Assume `favorite_sports` has these selected values:

* `Basketball` with ID `1`
* `Dancing` with ID `3`
* `Sailing` with ID `4`
* `Soccer` with ID `5`

```
chosen(favorite_sports)
```

Returns the selected values as an array.

```ninox
["Basketball", "Dancing", "Sailing", "Soccer"]
```

```
chosen(favorite_sports, [1, 3, 5])
```

Returns `true` because all listed IDs are selected.

```
chosen(favorite_sports, 4)
```

Returns `true` because the option with ID `4` is selected.

```
chosen(favorite_sports, "Dancing")
```

Returns `true` because `Dancing` is selected.

```
chosen(favorite_sports, "Climbing")
```

Returns `false` because `Climbing` is not selected.

```
chosen(favorite_sports) = "Dancing"
```

Returns `true` only when `Dancing` is the only selected value.

Tips:

* Use `numbers()` when you need the selected IDs as an array for further processing.

## Combine a list of text values into one string <a href="#combine-a-list-of-text-values-into-one-string" id="combine-a-list-of-text-values-into-one-string"></a>

Use `join()` to return one string from all items in a string array or table result, separated by a separator you choose. Unlike `concat()`, `join()` lets you define exactly what goes between items, including commas, spaces, or line breaks.

`join()` has nothing to do with the SQL statement of the same name.

Use it when you want to:

* Display multiple tags in one line.
* Create CSV-style text for copy and paste.
* Output values line by line in a multiline text field.

`join([string], string)`

* `separator`: the text to insert between each item, for example, `","`, `" | "`, or `"\n"`

#### Let’s take a look at some examples: <a href="#lets-take-a-look-at-some-examples..1" id="lets-take-a-look-at-some-examples..1"></a>

```
join(["A", "B", "C"], "
")
```

Combines the array into one multiline string with a line break between each item.

The result is:

```
A
B
C
```

```
join((select customer where sales > 10000).name, "; ")
```

Returns the names of all customers with sales greater than `10000`, separated by semicolons.\
For readability it adds a space after the semicolon.<br>

```
let names := (select products).name; 
join(names, " | ")
```

Selects all product names and joins them with the separator `|` between each.\
For readability it adds a space before and after the separator.

Tips:

* Use `join()` when you need a separator other than a comma. Use `concat()` when commas are enough.
* Use a line break as the separator for multiline output, as shown above.&#x20;

## Break a text into parts you can loop through or analyze <a href="#break-a-text-into-parts-you-can-loop-through-or-analyze" id="break-a-text-into-parts-you-can-loop-through-or-analyze"></a>

Use `split()` to split a string into an array at each separator. The separator marks where the text should be split and is not included in the result. Use `splitx()` for complex cases or texts with multiple separators.\
Use it when you want to:

* Take a comma-separated list from a text field and process each item.
* Process imported text that combines multiple pieces of information in one field.
* Split structured values like names, addresses, or codes into separate parts.

`split(text, separator)`

* `text`: the original string you want to break into parts
* `separator`: the exact text that marks where to split, for example, `","` or `"|"`. Every occurrence of this separator starts a new element in the resulting list.

`splitx(text, regex)`

* `text`: the original string you want to break into parts
* `regex`: a "*regular expression*" that defines every possible separator.

{% hint style="info" %}
Using regular expressions will likely require some additional research. We recommend taking a look at [https://regex101.com/](https://regex101.com/ "mention") (external link) to test your regular expressions.
{% endhint %}

#### Let’s take a look at some examples: <a href="#lets-take-a-look-at-some-examples" id="lets-take-a-look-at-some-examples"></a>

```
split("Company Mainroad 5 10213 City", " ")
```

Splits the text at each space.

The script returns an array with `Company`, `Mainroad`, `5`, `10213`, and `City`.<br>

```
item(split("Company, Mainroad 5, 10213 City", ","), 0)
```

Splits the text at each comma, then returns the first item from the array.

The script returns `"Company"`.\
With `1`, it would return `"Mainroad 5"`.<br>

```
splitx("333A111&777-666", "\D")
```

Splits wherever the text contains a non-numeric character.

The script returns a list “333”, “111”, “777”, "666".

Tips:

* Combine `split()` with `item()` when you know the order of the split data and need one specific part.
* Patterns can split more than you expect; first test on a few sample values to confirm the list looks right.

## Search and replace a string with another <a href="#search-and-replace-a-string-with-another" id="search-and-replace-a-string-with-another"></a>

Use `replace()` for a simple search and replace in a string. It searches for a fixed string and replaces each match with another string. Both strings can have different lengths and can contain any representable character.

For example to:

* Search in a text for a certain string and replace it with another string.
* Set placeholders within text fields. You can then replace these with personalized content, for example when printing or sending emails.
* Remove unwanted characters from a text.

`replace(text, search, replacement)`

* `text`: the original string you want to search in
* `search`: the exact substring you want to find
* `replacement`: the text that should replace every occurrence of the `search` string

The search is case-sensitive.

#### Let’s take a look at some examples: <a href="#lets-take-a-look-at-some-examples.1" id="lets-take-a-look-at-some-examples.1"></a>

```
replace("Hello world!", "o", "a")
```

Replaces each `"o"` with `"a"`.\
The script returns `"Hella warld!"`.<br>

```
replace(MyText, "  ", " ")
```

Replaces all double spaces in `MyText` with a single space.<br>

```
replace("Hello ##FNAME##!", "##FNAME##", first_name)
```

The placeholder string `"##FNAME##"` is replaced by the content of the field or variable `first_name`.

If `first_name` is `Jimmy`, the script returns "Hello Jimmy!".

Tip: If you want to remove unwanted characters, use an empty string `""` as the replacement.

## Search and replace using patterns <a href="#search-and-replace-using-patterns" id="search-and-replace-using-patterns"></a>

Use `replacex()` when you need to search and replace with *regular expressions*, not just exact text. It extends `replace()` and gives you much more control when the text you want to change follows a pattern rather than a fixed value.

Use `replacex()` when `replace()` would require many separate calls or when the text to be changed is not identical in every case.

Use `replacex` when you want to:

* Remove or normalize all digits or special characters.
* Clean up formats like phone numbers, IDs, or codes.
* Replace multiple different separators with a single consistent one.
* Clean up imported data that contains unwanted characters.

`replacex(text, regex, replacement)`\
`replacex(text, regex, flags, replacement)`

* `text`: the original string you want to search in
* `regex`: a regular expression that describes what to find
* `flags`: optional regular expression flags
* `replacement`: the text that should replace every match of the pattern

If you want to remove characters, use an empty string `""` as the replacement.

#### Let's take a look at some examples:

```
replacex(phone_no, "\D", " ")
```

Replaces all non-digits in `phone_no` with spaces.\
`\D` means every character that is not a digit.<br>

```
replacex("A--B==C", "--|==", "|")
```

Normalizes multiple separators to a single one. It replaces each occurrence of `--` or `==` with `|`.\
The script returns “A|B|C”.<br>

```
replacex(MyText, "^ *", "g", "")
```

Removes leading spaces from the text variable `MyText`.

{% hint style="info" %}
Using regular expressions will likely require some additional research. We recommend taking a look at [https://regex101.com/](https://regex101.com/ "mention") (external link) to test your regular expressions.
{% endhint %}

### Extract text with a regular expression using `extractx()`

Use `extractx()` to return the first match from a text based on a regular expression.

Use it when you want to:

* Extract a filename, code, or ID from a larger text.
* Pull structured values from imported data.
* Reuse part of a text that follows a pattern.
* Post-process a regex match before returning it.

`extractx(string, string)`\
`extractx(string, string, string)`\
`extractx(string, string, string, string)`

* first `string`: the text you want to search in
* second `string`: the regular expression pattern
* third `string`: optional flags
* fourth `string`: optional extract expression such as `$1` or `$2`

`extractx()` returns a string.

#### Let’s take a look at some examples:

```ninox
extractx(text(my_attachment), "(.+)\/(.+)", "i", "$2")
```

Extracts the filename from the attachment path and returns `ImportantDocument.pdf`.

Tips:

* Use `extractx()` when you need the first matching part, not a full replacement.
* Use capture groups like `$1` or `$2` when only one part of the match is relevant.
* Use `testx()` to check whether a pattern matches before you extract it.

{% hint style="info" %}
Using regular expressions will likely require some additional research. We recommend taking a look at [https://regex101.com/](https://regex101.com/ "mention") (external link) to test your regular expressions.
{% endhint %}

## Extract a specific part of a text <a href="#extract-a-specific-part-of-a-text-for-reuse" id="extract-a-specific-part-of-a-text-for-reuse"></a>

Use `substr()` or `substring()` to extract only a part of a longer text. This is useful when your text has a consistent structure, for example, invoice numbers or codes, and you need a specific section such as a prefix, year, or short code.\
Both functions extract part of a text, but they work slightly differently: `substr()` starts at a position and optionally takes a certain number of characters, while `substring()` starts at a position and takes everything up to a given end position.

For example, to:

* Extract parts of identically structured data, for example, the prefix of an invoice number.
* Abbreviate values for comparison, for example, turning "Yes" and "No" into "Y" and "N".

`substr(text, start)`\
`substr(text, start, length)`

* `text`: the original string you want to extract a part from
* `start`: the position where the extract should begin. The start is zero‑based, the first character has position `0`.
* `length` (optional): how many characters to return starting from `start`. If you skip `length`, the extract runs from `start` to the end of `text`.

`substring(text, start, end)`

* `text`: the original string you want to extract a part from
* `start`: the position where the extract should begin. The start is zero‑based, the first character has position `0`.
* `end`: the position after the last character you want to include. The end is exclusive, the character at `end` is not part of the result.

Note: If the `end` value is smaller than the `start` value, Ninox automatically swaps them: the smaller number becomes the start position and the larger one becomes the end position.

#### Let’s take a look at some examples:

```
substr(ninox_example, 11)
```

Returns a new string out of the given text with a given start.\
If the field `ninox_example` contains the text “Hello world!”, this script returns “!”.\
The exclamation mark is at position 11 when we start counting at 0: `H=0, e=1, l=2, l=3, o=4, space=5, w=6, o=7, r=8, l=9, d=10, !=11`.<br>

```
substr(ninox_example, 0, 5)
```

Returns a new string of the given length out of the text, starting at position 0.\
If the field `ninox_example` contains the text “Hello world!”, this script returns “Hello”: `H=0, e=1, l=2, l=3, o=4, ...`.<br>

```
substring(ninox_example, 4, 7)
```

Returns a new string out of the given text with a given start and a given end.\
If the field `ninox_example` contains the text “Hello world!”, this script returns “o w”.\
Characters at positions 4, 5, and 6: `H=0, e=1, l=2, l=3, o=4, space=5, w=6`; the character at position 7 is not included.

## Measure the size of text or lists <a href="#measure-the-size-of-text-or-lists" id="measure-the-size-of-text-or-lists"></a>

Use `length()` to return the number of characters in a string or the number of items in an array. Spaces count as characters. In arrays, every item counts, including empty strings and `null`.

Use it when you want to:

* Calculate the size of an array.
* Compare string lengths.
* Check whether a field contains a certain number of characters.
* Count the remaining characters from a specific point together with `substr()` or `index()`.

`length(string)`\
`length([any])`

* `string`: the text whose characters you want to count
* `[any]`: the array whose items you want to count

#### Let’s take a look at some examples: <a href="#lets-take-a-look-at-some-examples.3" id="lets-take-a-look-at-some-examples.3"></a>

```
length("Ninox is great!")
```

Counts all characters in the text, including spaces.\
The script returns "15".<br>

```
length(["A", "B", "", "D", null])
```

Counts all items in the array. Empty strings and `null` still count as items.\
The script returns "5".

Tips:

* If you only want to count matching records or non-empty values, use a more specific function such as `count()`.
* If you need the number of characters from a specific starting position in a text, combine `length()` with `substr()` or `index()`.

## Find the position of text inside another text <a href="#find-the-position-of-text-inside-another-text" id="find-the-position-of-text-inside-another-text"></a>

Use `index()` to return the start position of the first match in a string or an array. Unlike `contains()`, it does not just tell you whether a match exists. It returns the numeric position of that match. Counting starts at `0`.

`index(text, search)` `index([any], any)`

* `text`: the original string you want to search in
* `[any]`: the array you want to search in
* `search` / `any`: the value you are looking for

For strings, `index` returns the position of the first character of the first match. For arrays, it returns the position of the first identical item.

#### Let’s take a look at some examples: <a href="#lets-take-a-look-at-some-examples.4" id="lets-take-a-look-at-some-examples.4"></a>

```
index("Ninox is great!", "ox")
```

Returns the position of the first match inside the string.\
The script returns `3`.<br>

```
index("Ninox is great!", "N")
```

The first character matches at the start of the string.\
The script returns `0`.<br>

```
index("Ninox is great!", "oX")
```

This does not match because string matching is case-sensitive.\
The script returns `-1`.<br>

```
let myItems := [1, 2, 3, 4];
index(myItems, 3)
```

Returns the position of the matching array item.\
The script returns `2`.<br>

```
let myItems := ["A", "C", "D", "E", "F", "B"];
index(myItems, "D")
```

Returns the position of `"D"` in the array.\
The script returns `2`.<br>

```
index(["Ninox is great!"], "ox")
```

This returns `-1` because the array does not contain an item exactly equal to `"ox"`.

Tips:

* `index()` returns `-1` when no exact match is found.
* For strings, `index()` is case-sensitive. Use `lower()` or `upper()` when you want a case-insensitive check.

## Check if text or a list contains an exact value <a href="#check-if-text-or-a-list-contains-an-exact-value" id="check-if-text-or-a-list-contains-an-exact-value"></a>

Use `contains()` to check whether a string or an array contains the exact match you are looking for. The result is always a boolean: `true` for a match and `false` when no match is found.

Use it when you want to:

* Search for keywords in a text field.
* Test whether an array contains a specific value.

`contains(string, string)`\
`contains([any], any)`

* `string`: the text you want to search in
* `[any]`: the array you want to search in
* `string` / `any` (second argument): the value you are looking for

For strings, `contains` is case-sensitive. For arrays, an exact match means the searched value is equal to one of the items.

If you also need the position of a match, use `index()` instead.

#### Let’s take a look at some examples: <a href="#lets-take-a-look-at-some-examples.5" id="lets-take-a-look-at-some-examples.5"></a>

```
contains("Hello world!", "Hello")
```

Checks if `"Hello world!"` contains `"Hello"`.\
The script returns `true`.<br>

```
contains("Hello world!", "hello")
```

The capitalization does not match and `contains()` is case-sensitive.\
The script returns `false`.

To ignore case, format the text first with `lower()`:

```
contains(lower("Hello world!"), "hello")
```

Both the text and the search term are lower case, so this returns `true`.<br>

```
contains(["A", "B", "C"], "B")
```

Checks whether `"B"` appears in the array `["A", "B", "C"]`.\
The script returns `true`.<br>

```
contains(["A", "B", "C"], "D")
```

`"D"` is not in the array.\
The script returns `false`.<br>

```
contains([{ name: "Sam" }], { name: "Sam" })
```

This returns `false`. JSON objects are not matched by content. They are matched by identity.

## Change the letter case of text <a href="#change-the-letter-case-of-text" id="change-the-letter-case-of-text"></a>

Use `upper()`, `lower()`, and `capitalize()` to change how letters in a text are written. This helps you clean up messy or inconsistent input, standardize values before comparing them, and format names, labels, and messages so they look consistent in print layouts, reports, and emails.

* `upper()` converts lowercase characters in a text to uppercase.
* `lower()` converts uppercase characters in a text to lowercase.
* `capitalize()` converts the first character of each word in a text to a capital letter and the remaining characters to lowercase.

`upper(string)`\
`lower(string)`\
`capitalize(string)`

* `string`: the text you want to change

#### Let’s take a look at some examples: <a href="#lets-take-a-look-at-some-examples.6" id="lets-take-a-look-at-some-examples.6"></a>

```
upper("upPer")
```

Converts lowercase characters to uppercase. Other characters stay unchanged.\
The script returns `"UPPER"`.<br>

```
contains(upper("With Ninox you can build great databases"), upper("database"))
```

This is useful for case-insensitive comparisons.\
The script returns `true`.<br>

```
lower("LOwER")
```

Converts uppercase characters to lowercase. Other characters stay unchanged.\
The script returns `"lower"`.<br>

```
contains(lower("With Ninox you can build great databases"), lower("DATABASE"))
```

This is useful for case-insensitive comparisons.\
The script returns `true`.<br>

```
capitalize(last_name)
```

If the field "Last name" contains "doe", the script returns "Doe".<br>

```
capitalize("John doe")
```

Capitalizes the first letter of each word and returns "John Doe".<br>

```
last_name := capitalize(last_name)
```

This updates the field value directly.\
If the field contains "roe", the result is "Roe".

Tips:

* When you compare text and do not care about capitalization, apply `lower()` or `upper()` on both sides of the comparison. A common mistake is to normalize only one side, which can still give a mismatch if the other side uses different case.
* Use `capitalize()` only for data that should follow name-style capitalization. It is not a good fit for codes like `AB-123` or acronyms such as `HR` or `IT`, where changing the case would actually damage the meaning.
* Add `capitalize()` in the automation "After Update" when names or labels should always start with a capital letter.

### Execute text as Ninox script, including table or field internal names

This fuction enables you to create dynamic text so that you can also use internal table or field names in a dynamic manner.

Please keep in mind that you need to name the tables or fields with their internal name and not the label.

#### Lets have look at some examples:

If you want to pick a table with choice field to see stats of the chosen table. This way you do not need to save the skript for each table in an `if ... then ... else` or `switch ... case` function, which will help to make the function better readabl.

```
let myTable := lower(text(table_choice));
eval("cnt(select " + myTable + ")", this)
```

Here is another example that shows how different tables can be displayed depending on the current user.

## Format, clean, and style text values <a href="#format-clean-and-style-text-values" id="format-clean-and-style-text-values"></a>

Use these functions when you already have text and want to clean it up, pad it, or style it for display. Use them when you want to fine‑tune how text looks and behaves in your app. Use them to:

* Remove extra spaces
* Add characters so the text has a fixed length
* Convert values to text
* Style text with colors and icons

They are especially useful when you prepare data for printing, exports, or dashboards where you need a consistent look and feel.

### Remove extra spaces with `trim()` <a href="#remove-extra-spaces-with-trim" id="remove-extra-spaces-with-trim"></a>

Use `trim()` to remove leading and trailing spaces from a text. This is especially useful when text is copied from another source and unwanted spaces are added at the beginning or end. `trim()` does not change spaces inside the text.

`trim(string)`

* `string`: the text where you want to remove spaces at the beginning or end

#### Let’s take a look at an example:

```
last_name := trim(last_name)
```

Removes leading and trailing spaces from the field `last_name`.\
If the field contains `" Doe "`, the result is "Doe".

Tip: Add this to the trigger after update of a text field when you want every new or changed value cleaned automatically.

### Pad text to a fixed length with `lpad()` and `rpad()` <a href="#pad-text-to-a-fixed-length-with-lpad-and-rpad" id="pad-text-to-a-fixed-length-with-lpad-and-rpad"></a>

Use `lpad()` and `rpad()` to make a string reach a certain total length by filling up missing characters at the beginning or at the end. This is useful when codes must have a fixed length or when you align values in reports and print layouts.

`lpad()` adds padding at the beginning of a string, on the left side. The padding characters repeat until the total length is reached. `rpad()` adds padding at the end of a string, on the right side. The padding characters repeat until the total length is reached.

`lpad(string, length, padding)`\
`rpad(string, length, padding)`

* `string`: the original text
* `length`: the target total length of the result
* `padding`: the characters used to fill the missing space

If the original text already reaches or exceeds `length`, it stays unchanged.

#### Let's take a look at some examples:

```
lpad("A text", 20, "+ ")
```

Pads `"A text"` on the left with `"+ "` until the total length is 20 characters.\
The script returns "+ + + + + + + A text".<br>

```
lpad(text(123), 8, "0")
```

First converts the number `123` to text, then pads on the left with zeros to reach length 8.\
The script returns "00000123".<br>

```
rpad("A text", 20, " +")
```

Pads `"A text"` on the right with `" +"` until the total length is 20 characters.\
The script returns "A text + + + + + + +".<br>

```
rpad(text(123), 8, "0")
```

Pads on the right with zeros to reach length 8.\
The script returns "12300000".

### Convert values to plain text with `string()` and `text()` <a href="#convert-values-to-plain-text-with-string-text-and-text" id="convert-values-to-plain-text-with-string-text-and-text"></a>

Use `string()` and `text()` to turn Ninox values into text you can display, join, or export. This is helpful when you want to build readable labels, combine values with text, or pass text to emails, print layouts, or external tools.\
`string()` converts a value to its raw string form and does not take formatting into account.\
`text()` converts a value to a readable string and can reflect format options such as date, time, or number formats.

`string(value)`\
`text(value)`

* `value`: any Ninox value you want as text, such as a number, date, choice, or array

#### Let's take a look at some examples:

```
alert("Today is " + text(today()))
```

Shows a message where the date is converted to readable text.\
The script returns a popup like `"Today is 10/25/2026"` depending on your date format.<br>

```
text(status)
```

If the choice field `status` currently shows `In progress`, the script returns the text "In progress".<br>

```
string(new_year_s_eve)
```

If the date field "New Year's Eve" is set to 31 Dec 2026, this returns the internal numeric value for that date.<br>

```
string(favorite_sports)
```

If `favorite_sports` is a multiple-choice field, this returns the internal code such as `"d1"` rather than the visible labels.

Tips:

* Use `string()` when you need the raw stored value.
* Use `text()` when you need readable output that reflects display formatting.
* For multiple-choice fields, `text()` gives you the visible labels, while `string()` can return the internal hexadecimal value.

### Style text with colors and icons using `styled()`, `color()`, `icon()`, and `html()` <a href="#style-text-with-colors-and-icons-using-styled-and-color" id="style-text-with-colors-and-icons-using-styled-and-color"></a>

Use `color()` to return a color value, `icon()` to return an icon value, `html()` to return rich text, and `styled()` to apply colors and an optional icon to text. Styling converts the result to the `styled` data type.

`color(name)`\
`color(r, g, b)`\
`color(r, g, b, a)`\
`color(choice)`\
`icon(choice)`\
`icon(string)`\
`html(any)`

* `name`: a color name or code such as `"blue"` or `"#4970FF"`
* `r, g, b`: red, green, and blue components as numbers
* `a`: optional opacity between 0 and 1
* `choice`: a choice field whose selected option has a defined color
* `string`: the icon name you want to return
* `any`: the value you want as rich text with HTML rendering

`color()` accepts any valid color identifier such as names, hex values, RGB, or RGBA values.

`icon()` returns an icon value for an icon or logic field. You can also return the icon from a selected choice field option.

`html()` returns a rich text value. Basic HTML tags, lists, tables, and inline styles render where rich text is supported.

`styled()` returns a styled object. In a logic field, Ninox shows the styled text instead of plain text.

`styled(text, background)`\
`styled(text, background, icon)`\
`styled(text, background, fontColor, icon)`

Use these data types for the above parameters:\
`styled(text, color)`\
`styled(text, color, icon)`\
`styled(text, color, color, icon)`\
`styled(text, JSON)`

* `text`: the text to show
* `background`: a color or color name for the background
* `fontColor`: a color for the text itself
* `icon`: the icon name to show next to the text
* `JSON`: a JSON object such as `{ color: "black", background: "orange", icon: "warn" }`

If you want to skip one or more parameters without changing the parameter order, pass an empty string `""` for each parameter you want to skip. Ninox then uses the default value for that parameter.\
For example, if you skip the font color, Ninox automatically uses black or white to keep enough contrast against the background.

#### Let's take a look at some examples:

```
color("blue")
```

Returns a blue color, but not the Ninox blue.<br>

```
color("#4970FF")
```

Returns the color with the hex code #4970FF (blue).<br>

```
color(73, 112, 255)
```

Returns the Ninox blue as an RGB color value.<br>

```
color(73, 112, 255, 0.5)
```

Returns a color made from the RGB values "73", "112", and "255", with 50% opacity.<br>

```
color(status)
```

Returns the color of the option that is selected in the choice field "Status".<br>

```
styled("Warning!", "", "red", "warn")
```

Shows `Warning!` in red with a warning icon left of the text.\
The empty background lets Ninox use the default background. Only the font color and icon are set.<br>

```
styled("Warning!", background, font_color, icon)
```

Uses the values from the fields `background`, `font_color`, and `icon` to style the text and show the selected icon to the left.<br>

```
styled(text(balance), if balance < 0 then "lightred" else "lightgreen" end)
```

Shows the account balance with a red background if it is below zero, or green if it is zero or above.<br>

```
styled("Info", { background: "#4970FF", color: "white", icon: "info" })
```

Uses a JSON object to define background color, font color, and icon in one place.

```
icon(my_choice_field)
```

Returns the icon from the selected option in the choice field.

```
icon("heart")
```

Returns the `heart` icon.

```ninox
html("<b>Ninox</b> is <i>great</i>!")
```

Returns a rich text value that renders the bold and italic formatting where rich text is supported.

```ninox
rich_text := html("<div style=""height:100px;width:100px;background-color:red;""><b>Ninox</b> is <i>great</i></div>!")
```

Writes formatted rich text into the `rich_text` field.

Tips:

* Use `html()` only where rich text is supported.
* In a normal text field, HTML tags are shown as plain text, but in a rich text field, the HTML is rendered.

## Turn numbers, dates, and times into text and format them <a href="#turn-numbers-dates-and-times-into-text-and-format-them" id="turn-numbers-dates-and-times-into-text-and-format-them"></a>

Use `format()` when you want to turn numbers, dates, times, and appointments into text and control exactly how they look.\
This is helpful when you:

* Show values in print layouts or emails.
* Add currency or units to a number which is not taken from a number field with a set currency.
* Standardize how dates and times look across your app.

`format()` returns a text value. It does not change the original number or date.

`format(number, pattern)`\
`format(date, pattern)`\
`format(date, pattern, language)`\
`format(appointment, pattern)`\
`format(appointment, pattern, language)`\
`format(timestamp, pattern)`\
`format(timestamp, pattern, language)`\
`format(time, pattern)`

* `number` / `date` / `time` / `appointment` / `timestamp`: the value you want to turn into text
* `pattern`: a text expression that describes the format you want to display
* `language`: the language code for the result, for example, `"en"` or `"de"`

All parts of the format expression are optional. If you use an empty pattern such as `""`, the value stays unformatted.

### Format numbers with `format()` <a href="#format-numbers-with-format" id="format-numbers-with-format"></a>

Use `format()` to turn a number into text with the prefix and suffix, exact separators, decimals, and units you need.

When you build a number format, define these parts in order:

* Optional prefix, for example, `$`
* Whether to show a thousands separator
* How many decimal places to show
* Optional suffix or unit, for example, `€`
* Decimal separator style
* Thousands separator style

{% hint style="info" %}
Results can differ based on your locale and format settings. The same pattern may show periods or commas differently across regions.
{% endhint %}

#### Let’s take a look at some examples:

```
format(238597, "")
```

Shows the number without special formatting: "238597".

```
format(238597, ".00")
```

Shows two decimal places: "238597.00" or "238597,00". Depending on your locale separated with period or comma.

```
format(2385.97, "0.000#,#")
```

Shows three required decimal places and an optional extra digit.\
Depending on your locale, the script returns `"2387,970"` or `"2387.970"`.<br>

```
format(2385.97, "$#,.#0,0")
```

Adds a dollar sign, a thousands separator, and two decimal places: "$2,385.97".

```
format(2385.97, "#,##0.00 €#,#0.0")
```

Uses a format often used in Europe with comma as decimal separator and period as thousands separator: "2.385,97 €".

```
format(12345, "0000000000")
```

Pads a number with leading zeros to reach a fixed length: `0000012345`.

### Format dates and times with `format()` <a href="#format-dates-and-times-with-format" id="format-dates-and-times-with-format"></a>

Use `format()` to turn dates, times, and timestamps into readable text.

You can:

* Spell out day and month names.
* Control the order of day, month, and year.
* Include or skip time parts.
* Use a specific language for month and weekday names.

#### **Let's take a look at some examples:**

```
format(date, "ddd, Do MMMM YYYY")
```

Formats the date in a long, readable way.\
`ddd` represents the weekday name, like `Mon` or `Wed`. `Do` represents the day of month `D` and the ending `o`, like `1st` or `23rd`.\
If the date is 05/31/2026, the script returns "Mon, May 31, 2026" in US format or "Mon, 31st May 2026" in UK format.<br>

```
format(date, "YYYY-MM-DD")
```

Shows the date in ISO style, for 31. May 2026 the script returns "2026-05-31".<br>

```
format(date, "ddd, Do MMMM YYYY", "us")
```

Shows the date in US style with English weekday and month names. For 25. May 2026 the script returns "Mon, May 25, 2026".<br>

```
format(myTime, "HH:mm")
```

Formats a time value with hours and minutes, for example, "09:30".<br>

```
format(now(), "YYYY-MM-DD HH:mm:ss")
```

Formats the current date and time from `now()` in a common log format: "2026-05-31 15:06:27".<br>

```
format(now(), "X")
```

Shows the current date and time as Unix time without milliseconds. It provides a simple, timezone-independent way to represent a specific moment in time as a single integer. If the date is 26. May 2026, the script returns the timestamp without milliseconds "1774479600".<br>

```
format(now(), "x")
```

Shows the current date and time as Unix time with milliseconds. If the date is 17. May 2026 (09:32:41 am), the script returns the timestamp including milliseconds "1779010361000".<br>

```
format(myAppointment, "YYYY-MM-DD HH:mm")
```

Formats the start date and time of an appointment variable as text.<br>

```
format(myAppointment, "dddd, D. MMMM YYYY, HH:mm", "fr")
```

Formats the appointment start date and time in French, with localized weekday and month names.

Tips:

* Your locale and language settings affect month names and some default separators. The same format can look different across regions, for example, `$2,385.97` versus `2.385,97 €`.

## Work with JSON and XML for advanced integrations <a href="#work-with-json-and-xml-for-advanced-integrations" id="work-with-json-and-xml-for-advanced-integrations"></a>

Use `formatJSON()` and `formatXML()` to turn JSON data into a string. This is useful when you:

* Work with APIs that return or expect JSON or XML.
* Want to inspect an incoming JSON object.
* Need to convert JSON to XML text.

These functions are for advanced users who are familiar with JSON and XML. The results are plain text values. Ninox does not interpret them automatically.

### Turn a JSON object into text with `formatJSON()` <a href="#turn-a-json-object-into-text-with-formatjson" id="turn-a-json-object-into-text-with-formatjson"></a>

Use `formatJSON()` to convert a valid JSON object into a JSON string. This is useful when you want to inspect the content of an incoming JSON object or modify it with other text functions.

`formatJSON(JSON)`

* `JSON`: a JSON object

#### Let’s take a look at an example:

{% code overflow="wrap" %}

```
let databaseURL := "https://api.ninoxdb.de/v1/teams/" + teamId() + "/databases/" + databaseId() + "/tables/" + tableId(this); 
let myAPIKey := "Bearer abcd1234-0000-xxxx-zzzz-1a1aa1aaa1a111"; 
let response := http("GET", databaseURL, { Authorization: myAPIKey }, null); 
'Text' := formatJSON(response)
```

{% endcode %}

This script:

* Calls the Ninox API with a `GET` request.
* Uses an API key. Replace the example key with your own personal API key.
* Gets a JSON response as a JSON object.
* Converts that JSON object to a JSON string with `formatJSON()`.
* Stores the JSON text in the field `Text` so you can inspect the response.

Without `formatJSON()`, the result is not useful for reading in a text field.

You’ll get a JSON string with the data of your current table, for example:

{% code overflow="wrap" %}

```json
{"result":{"id":"I","name":"Table1","fields":[{"id":"A","name":"Text","type":"string"},{"id":"B","name":"Number","type":"number"},{"id":"D","name":"Text 2","type":"string"}]}}
```

{% endcode %}

### Convert JSON to XML text with `formatXML()` <a href="#convert-json-to-xml-text-with-formatxml" id="convert-json-to-xml-text-with-formatxml"></a>

Use `formatXML()` to convert a JSON object into XML text. XML is, alongside JSON, one of the most common formats for exchanging data. This makes `formatXML()` especially useful when you connect Ninox to external servers by API.

`formatXML(JSON)`\
`formatXML(JSON, pretty)`

* `JSON`: a JSON object you want to convert to XML string
* `pretty`: `true` or `false`. If `true`, the XML string is optically structured with indentation and line breaks.

#### Let’s take a look at an example:

{% code overflow="wrap" %}

```
formatXML({ 
    contact: { 
        @type: "Person", 
        firstName: { 
            @: 'First Name' 
        }, 
        lastName: { 
            @: 'Last Name' 
        }, 
        phone: [{ 
                @type: "Mobile", 
                @: Mobile 
            }, { 
                @type: "Phone", 
                @: Phone 
            }] 
    } 
}, true)
```

{% endcode %}

This converts the JSON object into an XML string. With `pretty` set to `true`, the result is formatted for easier reading:

{% code overflow="wrap" %}

```xml
<?xml version="1.0" encoding="utf-8"?> 
<contact type="Person"> 
    <firstName>Steve</firstName> 
    <lastName>Rogers</lastName> 
    <phone type="Mobile">(+1) (202) 123 45 67</phone> 
    <phone type="Phone">+1.151.11 ++66 14 66</phone> 
</contact>
```

{% endcode %}

You can then send this XML text to another system or save it for export.

Tips:

* Use `formatJSON()` when you want to see or store JSON data as string, or when you want to process it further with text functions like `replace()` or `split()`.

## Check text with regular expressions

Use `testx()` when a normal exact-text search is not flexible enough.

### Check whether text matches a regular expression with `testx()`

Use `testx()` to return `true` when a text matches a regular expression.

Use it when you want to:

* Check whether a text contains a value that follows a pattern.
* Validate imported text before you process it.
* Detect placeholders, IDs, or coded values in free text.

`testx(string, string)`\
`testx(string, string, string)`

* first `string`: the text you want to check
* second `string`: the *regular expression*
* third `string`: optional flags

`testx()` returns a boolean.

#### Let’s take a look at some examples:

```ninox
testx("Hello [username]! You have [number of messages] messages!", "\[(\w|\s)*\]")
```

Returns `true` because the text contains content in square brackets that matches the pattern.

Tips:

* Use `testx()` when you only need a yes-or-no result. Otherwise, use `extractx()` or `replacex()`.

{% hint style="info" %}
Using regular expressions will likely require some additional research. We recommend taking a look at [https://regex101.com/](https://regex101.com/ "mention") (external link) to test your regular expressions.
{% endhint %}

## Turn CSV, JSON, and XML text into data you can work with <a href="#turn-csv-json-and-xml-text-into-data-you-can-work-with" id="turn-csv-json-and-xml-text-into-data-you-can-work-with"></a>

Use `parseCSV()`, `parseJSON()`, and `parseXML()` to turn text into structured data that Ninox can work with. This is useful when you:

* Import or receive data as text, but you need it as one of these structured data formats to process it further.
* Want to export your Ninox data as CSV, JSON, or XML, for example, to communicate with other integrations via API.

`parseCSV()` works with CSV text.\
`parseJSON()` converts a JSON string to a JSON object.\
`parseXML()` converts an XML string to a JSON object.

### Turn CSV text into rows and columns with `parseCSV()` <a href="#turn-csv-text-into-rows-and-columns-with-parsecsv" id="turn-csv-text-into-rows-and-columns-with-parsecsv"></a>

Use `parseCSV()` to turn CSV text into structured data you can loop through. Use it for pasted spreadsheet data, imported files, or CSV text from integrations.

`parseCSV(string, options)`

* `string`: the CSV text you want to parse, for example,

{% code overflow="wrap" %}

```
"Name,Age
Kiran,42
Lisa,27"
```

{% endcode %}

* `options`: optional JSON object:
  * `firstLineIsHeader` (boolean, default `false`): if `true`, Ninox uses the first line as column names and returns JSON objects. If `false`, Ninox returns each row as a list of text values.
  * `separator` (string, optional): the character between fields, such as `","` or `";"`. If you leave this out, Ninox tries to detect it automatically.
  * `textQuote` (string, optional): the character used to quote text fields. The default is `"`.

`parseCSV()` returns one of these structures:

* A list of JSON objects when `firstLineIsHeader: true`
* A list of text arrays when `firstLineIsHeader: false`

#### Let's take a look at some examples:

Default behavior:

```
parseCSV("Name,Age
Kiran,42
Lisa,27", {})
```

Returns a list where each row is a list of text values:

```json
[
    ["Name", "Age"], 
    ["Kiran", "42"], 
    ["Lisa", "27"]
]
```

\
Use the first line as a header:

```
parseCSV("Name,Age
Kiran,42
Lisa,27", { firstLineIsHeader: true })
```

Returns a list of JSON objects with keys from the header line:

```json
[
    { 
        Name: "Kiran", 
        Age: "42" 
    }, 
    { 
        Name: "Lisa", 
        Age: "27" 
    }
]
```

\
Custom separator:

```
parseCSV("Name;Age
Kiran;42
Lisa;27", { separator: ";", firstLineIsHeader: true })
```

Reads `;` as separator and returns:

```json
[
    { 
        Name: "Kiran", 
        Age: "42" 
    }, 
    { 
        Name: "Lisa", 
        Age: "27" 
    }
]
```

\
Custom quote character: You can set a `textQuote` character, such as a single quote `'`, to handle fields with quoted text specifically.

```
parseCSV("Name,Note
Kiran,'Team lead, Berlin'
Lisa,'Works remote, Lisbon'", {
  firstLineIsHeader: true,
  textQuote: "'"
})
```

Treats `'` as the quote character, so commas inside the note stay in the same field:

```json
[
  { Name: "Kiran", Note: "Team lead, Berlin" },
  { Name: "Lisa", Note: "Works remote, Lisbon" }
]
```

Without a matching `textQuote` setting, quoted values stay exactly as they appear in the input. For example:

```
parseCSV("Name,Age
Kiran,42
'Lisa',27", {
  firstLineIsHeader: true
})
```

returns:

```json
[
  { Name: "Kiran", Age: "42" },
  { Name: "'Lisa'", Age: "27" }
]
```

Tips:

* Set `firstLineIsHeader: true` when you want to access values by name, for example `row.Name`.
* Leave it `false` when you only need raw rows and columns.
* If you do not set `separator`, Ninox auto-detects common delimiters such as commas or tabs.
* `textQuote` is optional. Unquoted fields still parse normally.

### Turn a JSON string into a JSON object with `parseJSON()` <a href="#turn-a-json-string-into-a-json-object-with-parsejson" id="turn-a-json-string-into-a-json-object-with-parsejson"></a>

Use `parseJSON()` to convert a JSON string into a JSON object you can work with in Ninox. This is useful for API responses, imported files, or JSON stored in a text field.

`parseJSON(string)`

* `string`: a valid JSON string

The string must be valid JSON. Otherwise, the result is not usable.

#### Let's take a look at an example:

```
parseJSON("{ ""test"": 123 }")
```

Converts the JSON text into a JSON object:

```json
{ "test": 123 }
```

You can then access values from the JSON in your logic.

For example, you can use it when you:

* Receive JSON from an API using `http()`.
* Need to read values from a JSON string stored in a field.
* Want to modify a JSON object and pass it on in `http()`.

Tips:

* Use double quotes `""` for quotes inside the JSON string.

### Turn an XML string into a JSON object with `parseXML()` <a href="#turn-an-xml-string-into-a-json-object-with-parsexml" id="turn-an-xml-string-into-a-json-object-with-parsexml"></a>

Use `parseXML()` to convert an XML string into a JSON object you can work with in Ninox. This is especially useful when you connect to external services by API and need to process incoming XML data. XML is a common exchange format alongside JSON.

`parseXML(string)`

* `string`: a valid XML string

#### Let's take a look at an example:

```ninox
let xml := "<?xml version=""1.0"" encoding=""UTF-8""?>
<note>
    <to>John Doe</to>
    <from>Ninox</from>
    <heading>Contact request</heading>
    <body>Please contact me!</body>
</note>";
parseXML(xml)
```

Returns a JSON object similar to:

```json
{"note":{"to":{"@":"John Doe"},"from":{"@":"Ninox"},"heading":{"@":"Contact request"},"body":{"@":"Please contact me!"}}}
```

You can then read values from that JSON object in your logic.

Tips:

* To go the other way (from structured data back to text), use `formatJSON` for JSON and `formatXML` for XML.
* If you have an XSD schema, validate the XML before you parse it.
* An invalid XML string returns a parse error.

See also:

* [Numbers and math](/ninox-scripting/automate-your-workflows/work-with-functions/numbers-and-math.md) for converting text to numbers and preparing values for calculations.
* [Dates and time](/ninox-scripting/automate-your-workflows/work-with-functions/dates-and-time.md) for formatting dates, times, and timestamps as readable text.
* [Integration and HTTP](/ninox-scripting/automate-your-workflows/work-with-functions/integration-and-http.md) for sending text payloads, parsing responses, and working with XML in integrations.
* [Location and devices](/ninox-scripting/automate-your-workflows/work-with-functions/location-and-devices.md) for building safe URLs and encoding query values.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ninox.com/ninox-scripting/automate-your-workflows/work-with-functions/text-and-strings.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
