All articles

Text Reverse: why "reversing text" is harder than it sounds

"Sator Arepo Tenet Opera Rotas" is a Latin word square found scratched into Roman ruins nearly two thousand years ago — read forwards, backwards, top-to-bottom, or bottom-to-top, the same five words appear every time. Reversing plain Latin-alphabet text like this is mechanically trivial; the interesting edge cases only show up once emoji or accented scripts enter the picture.

What a grapheme cluster is

What a person perceives as "one visible character" is sometimes made up of several code points in Unicode — a family emoji (👨‍👩‍👧), for instance, is actually several separate emoji joined together with a special zero-width joiner character. Such a combination is called a grapheme cluster.

Why a naive reverse breaks everything

If you reverse a string by individual code points rather than grapheme clusters, the joiner ends up in the wrong place, and instead of one visible emoji you get a set of separate, unrelated characters — often showing up as "broken" boxes or random emoji instead of the original.

A correct reverse

A proper implementation first splits the string into grapheme clusters (accounting for joiners, modifiers, and combining characters), and only then reverses the order of those clusters, not the individual code points within them.

Why you need this

  • Checking a palindrome like "A man, a plan, a canal – Panama" or creating a "mirrored text" effect.
  • Demonstrating or diagnosing a Unicode-handling bug in code.
  • Recreational or educational tasks that need a correct reversal of text containing emoji.

Combining diacritical marks

The character "é," written as the base letter "e" plus a separate combining acute accent, is two code points linked by order: the accent always immediately follows the character it modifies. A naive code-point-by-code-point reverse swaps them, and the accent "detaches" from its letter and attaches to the neighboring one instead — a correct reverse has to keep the base character and its combining marks together as a single unit.

Try the tool