Verse Wiki — the Verse handbook for Blueprint authors
EXTRA

Strings Under the Hood: char, char32 & UTF-8 Encoding

The official docs drop one understated line — string is an alias for []char, and char is a UTF-8 code unit — and behind it hides a whole field of text-encoding knowledge. Why is 'e' a char while 'é' is a char32? Why doesn't a Chinese string's Length match the characters you count by eye? This page upgrades you from using strings to understanding them.

1. Two Kinds of Characters: char & char32

Verse has two character types — not a common arrangement among programming languages:

char — one UTF-8 code unit; think of it as one byte-sized slot of the encoded form.
char32 — one complete Unicode code point: the number assigned in the Unicode table to what a human perceives as a single character.

Character literals (characters written directly in quotes) all use single quotes, but the type is decided by the content: 'e' is an ASCII character that happens to take exactly one code unit in UTF-8, so it is a char; a character with a diacritic like 'é' takes multiple UTF-8 code units — more than a single char can hold — so its literal type is char32: only a full code point can store it.

char_demo.verse
# ASCII character: one UTF-8 code unit — type char
Letter:char = 'e'

# 'é' needs multiple UTF-8 code units — its literal is char32
# Accent:char32 = 'é'

The abilities of char and char32 are deliberately squeezed to the minimum: they can be compared (with the might-not-hold = and <>, so those go inside a Branch/if) and they can hold a value — no arithmetic, no case conversion. To do more with a character, the usual move is to promote it to a string via interpolation, "{Ch}", and work from there — exactly the move the Split implementation on this lesson's extra page pulls.

2. UTF-8: The Variable-Length Character Packing Trick

Unicode hands every character on Earth a number (a code point): Latin letters, Chinese characters, kana, emoji — everyone gets one. But how does a number get stored in memory? That's an encoding scheme's job, and UTF-8 is today's undisputed mainstream. Its core idea is variable-length packing:

Character kind Examples UTF-8 code units (typical)
ASCII letters / digits / basic punctuation e, 7, ! 1
Latin letters with diacritics é, ü 2
CJK characters 你, 剑 3
Emoji and other high code points All manner of emoji 4

The more common the character, the shorter its encoding — pure-English text stays extremely compact while the full Unicode repertoire remains expressible. The price: character count and code-unit count are no longer the same thing.

Which directly pays off the setup planted in Lesson 10: string is []char, an array of UTF-8 code units, so .Length counts code units, not eyeball characters. By UTF-8 arithmetic, "你好" most likely has a Length of 6, not 2 — if you validate the length of player names or chat text containing Chinese, never treat Length as a character count. Verifying it yourself takes two lines:

utf8_lab_device.verse
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/Diagnostics }

utf8_lab_device := class(creative_device):

    OnBegin<override>()<suspends>:void =
        English := "Verse"
        Chinese := "你好"
        Print("English length: {English.Length}")
        # Run it yourself: the number below is very likely not 2
        # Verify the exact count in the editor
        Print("Chinese length: {Chinese.Length}")

Blueprint translation: at start (Event BeginPlay) jot down the two strings, then two Print String nodes output each one's .Length — the English line will read 5, and the Chinese line most likely won't read 2. See the gap between code units and characters with your own eyes.

By the same token, grabbing Chinese[0] by index inside a Branch (if) fetches the first code unit, not the complete character 你 — a boundary you must keep in mind when processing multi-byte text character by character.

3. String Comparison: Code Point by Code Point, Case-Sensitive

String equality = and inequality <> are both might-not-hold tests, so they go inside a Branch (if), and the rule is blunt: compare code point by code point, case-sensitive. "Apple" = "apple" fails, because A and a are two different code points; there is no built-in ignore-case switch, and the standard library offers no ToUpper / ToLower to normalize case first — when you need it, write the mapping yourself (or design around it, say by turning player input into fixed options instead of free text).

Connect this page with the Lesson 10 main text and you hold the complete mental model of Verse strings: literals are the script, interpolation fills the blanks, string is an array of UTF-8 code units, and char / char32 are its smallest parts. You can use them, and you know what's underneath — and when your project handles Chinese text, that understanding is exactly why you'll step on fewer mines than everyone else.

4. Pop Quiz ★

What are the types of the literals 'e' and 'é'?

Why is using .Length to validate the character count of a Chinese player name unreliable?

Sources & Further Reading

This page draws on Epic's official documentation, with reference to the character-type chapter of the community handbook Book of Verse (community material — defer to the official docs and in-editor testing for details):

Official docs: string in Verse ↗
Community handbook: Book of Verse — Primitives ↗