# String Conversion — DTOS, STOD, RTOS, STOR, UPPER, LOWER

Source: https://rungs.dev/docs/ladder-logic/instructions/string-conversion

> The Ladder Logic conversion instructions in rungs.dev turn numbers into text and text into numbers, and change the case of letters, for displays, barcodes and serial replies.

A display shows text, and a barcode reader or a serial device sends text. Your logic works with
numbers. These instructions cross between the two: `DTOS` and `RTOS` write a number as text,
`STOD` and `STOR` read a number out of text, and `UPPER` and `LOWER` change the case of letters
so two pieces of text can be compared whatever case they were typed in.

Each one runs on every scan its rung is true, and does nothing on a false rung. Each one writes
its result into its last operand.

## DTOS — Number to Text [#dtos--number-to-text]

Writes the Source number as decimal text into the destination STRING.

| Name     | Type                            |
| -------- | ------------------------------- |
| `source` | `DINT`, `INT`, `SINT` or `REAL` |
| `dest`   | `STRING`                        |

```ladder
XIC(ShowCount)DTOS(PartCount,CountText)
```

With `PartCount` holding `-42`, `CountText` becomes `'-42'`. A `REAL` is made a whole number
first, the way `MOVE` stores a `REAL` into a `DINT`: a half goes to the even neighbour, so `2.5`
gives `'2'` and `3.5` gives `'4'`. `DTOS` clears the whole destination before it writes, so
nothing of the old text is left in it.

## STOD — Text to Whole Number [#stod--text-to-whole-number]

Reads the first whole number in the Source STRING and stores it in the destination.

| Name     | Type                    |
| -------- | ----------------------- |
| `source` | `STRING`                |
| `dest`   | `DINT`, `INT` or `SINT` |

```ladder
XIC(ReplyReady)STOD(Reply,Speed)
```

`STOD` skips everything up to the first digit, then reads digits until something that is not a
digit. A `-` counts only when it sits directly before the first digit:

| `source`      | `dest` |
| ------------- | ------ |
| `'1500 rpm'`  | `1500` |
| `'SPD=-20'`   | `-20`  |
| `'12.7'`      | `12`   |
| `'- 5'`       | `5`    |
| `'no digits'` | `0`    |

A number too large for a `DINT` is held to the `DINT` limit, `2147483647` or `-2147483648`,
and Studio shows a warning. Into an `INT` or a `SINT` the number then wraps as any store does,
so `'300'` into a `SINT` gives `44`.

## RTOS — REAL to Text [#rtos--real-to-text]

Writes the Source REAL as text into the destination STRING.

| Name     | Type     |
| -------- | -------- |
| `source` | `REAL`   |
| `dest`   | `STRING` |

```ladder
XIC(ShowTemp)RTOS(Temperature,TempText)
```

With `Temperature` holding `21.5`, `TempText` becomes `'21.5000000'`. The text always has nine
digits, written one of three ways:

| `source`                   | Written as               | Example                               |
| -------------------------- | ------------------------ | ------------------------------------- |
| `0.0001` up to `1`         | eight decimals           | `0.25` gives `'0.25000000'`           |
| `1` up to `10000000`       | nine digits in all       | `1234.5` gives `'1234.50000'`         |
| anything larger or smaller | nine digits, an exponent | `12345678.0` gives `'1.23456780e+07'` |

Zero gives `'0.0'`, and so does a number too close to zero for a `REAL` to hold normally. The
digits are the `REAL`'s own, so `0.1` gives `'0.10000000'` but `123.456` gives `'123.456001'`:
a `REAL` holds about seven digits exactly.

## STOR — Text to REAL [#stor--text-to-real]

Reads the first number in the Source STRING and stores it in the destination REAL.

| Name     | Type     |
| -------- | -------- |
| `source` | `STRING` |
| `dest`   | `REAL`   |

```ladder
XIC(ReplyReady)STOR(Reply,Pressure)
```

Like `STOD`, `STOR` starts at the first digit, with a `-` directly before it. It then reads a
decimal point and more digits, and an exponent such as `e3` or `E-2`. So `'P=2.75bar'` gives
`2.75` and `'1.5e3'` gives `1500.0`. Text starting `0x` reads as hexadecimal: `'0x1F'` gives
`31.0`. A number larger than a `REAL` holds, or closer to zero than
one holds, gives `Infinity` and a warning.

## UPPER and LOWER — Change Case [#upper-and-lower--change-case]

Copies the Source STRING into the destination STRING with its letters in upper case.

Copies the Source STRING into the destination STRING with its letters in lower case.

| Name     | Type     |
| -------- | -------- |
| `source` | `STRING` |
| `dest`   | `STRING` |

```ladder
XIC(CodeReady)UPPER(Typed,Code)
```

With `Typed` holding `'ab-12x'`, `Code` becomes `'AB-12X'`. Only the letters `a` to `z` and `A`
to `Z` change; digits, spaces and every other character stay as they are. To compare text
whatever case it was typed in, change both sides to the same case and compare those.

## A STRING with a broken LEN [#a-string-with-a-broken-len]

When the source's `LEN` is outside `0` to `82`, none of these instructions reads it. `UPPER` and
`LOWER` leave `dest` as it was, `STOD` and `STOR` store `0`, and Studio shows a warning that
names the STRING.

## Common Mistakes [#common-mistakes]

- Expecting `STOR` to read `'.5'` as `0.5`. It starts at the first digit, so it reads `5`. Write
  `'0.5'`.
- Expecting `STOD` to round. `'12.7'` gives `12`: it stops at the decimal point. Use `STOR`, then
  `MOVE` the `REAL` into a `DINT` to round it.
- Putting text in quotes into a conversion, such as `STOD('12',Speed)`. Put the text in a
  `STRING` tag and use the tag.

## Related [#related]

- [String instructions](https://rungs.dev/docs/ladder-logic/instructions/string) — join, find and cut text
- [MOVE](https://rungs.dev/docs/ladder-logic/instructions/move) — copy text into a STRING
- [String conversion in Structured Text](https://rungs.dev/docs/structured-text/instructions/string-conversion)