Bidirectional text rendering — the challenge of displaying text that mixes left-to-right and right-to-left scripts in the same line — is one of the most underappreciated problems in internationalisation, and reversing text naively (character by character) produces output that looks correct to Latin-script readers while being completely garbled for Arabic, Hebrew, or mixed-direction content
Text reversal as a concept seems simple: reverse the order of characters. For ASCII text, it is simple. For Unicode text that contains combining characters, emoji with modifiers, bidirectional control characters, or scripts with inherent direction, naive reversal produces results that range from visually odd to outright wrong — and understanding why reveals how Unicode actually works.
The Unicode bidirectional algorithm and what it actually controls
The Unicode Bidirectional Algorithm (UBA, Unicode Standard Annex #9) specifies how text renderers determine the visual display order of characters in mixed-direction text. It operates on several levels:
Implicit directional properties: each Unicode character has an assigned "bidi category" — Latin letters are "L" (strong left-to-right), Arabic and Hebrew letters are "R" (strong right-to-left), digits are "EN" (European Number, treated as weak), spaces are "WS" (whitespace), and so on.
The paragraph direction: determined by the first strong directional character in the paragraph. A paragraph starting with a Hebrew letter is a right-to-left paragraph; starting with a Latin letter, it's left-to-right.
Bidi control characters: explicit Unicode characters (LRM U+200E, RLM U+200F, LRE U+202A, RLE U+202B, LRO U+202D, RLO U+202E, PDF U+202C) that override the automatic direction determination. The RLO character (Right-to-Left Override) forces all subsequent characters to render right-to-left regardless of their inherent direction — this is the basis of the "Trojan Source" attack in code.
Reversing text naively vs reversing correctly
For a pure ASCII string, character-by-character reversal produces an intuitively correct result:
- "Hello World" → "dlroW olleH"
For Arabic text, character-by-character reversal is nonsensical. Arabic text is already stored in logical order (left to right as typed, displayed right to left by the rendering engine). Reversing the character codes produces incorrect Arabic text — different words spelled backwards — not mirror-image Arabic text.
For Hebrew mixed with numbers, the bidi algorithm places the numbers in their natural position within the Hebrew text. Reversing character codes scrambles both the Hebrew text and the number placement.
For emoji sequences, some emoji are composed of multiple Unicode code points:
- 👨👩👧 (family emoji) = U+1F468 (man) + U+200D (ZWJ) + U+1F469 (woman) + U+200D (ZWJ) + U+1F467 (girl)
- Reversing byte-by-byte or code-point-by-code-point reverses the sequence, potentially producing a different family emoji or a broken sequence of individual emojis
The Trojan Source attack: bidirectional text as a security vulnerability
The "Trojan Source" vulnerability (CVE-2021-42574), published by researchers at the University of Cambridge in 2021, exploited Unicode bidirectional control characters in source code to create programs that look correct to human reviewers but have different logic than they appear to:
The mechanism: inserting RLO (Right-to-Left Override) and similar bidi control characters into source code comments or string literals causes the rendering engine (the code editor or code review interface) to display characters in a different visual order than the compiler processes them. A comment that visually reads // Check if admin might actually contain code after the // that the compiler processes but the reviewer sees rendered differently due to bidi override.
Affected editors: most code editors that render Unicode faithfully without explicitly stripping bidi control characters — including VSCode (patched), GitHub's web interface (patched), and many others. The patches either strip bidi control characters from code views or display explicit warnings when they're present.
The connection to text reversal: RLO (U+202E) is effectively a "reverse display" instruction — it causes subsequent text to be rendered right-to-left. Knowing this exists, and that tools that process strings containing RLO characters may display them differently from how they're stored, is important for any tool that processes or displays user-provided text.
Palindromes and reversal as algorithms
Testing whether a string is a palindrome is a classic algorithmic problem that illustrates the correct approach to Unicode reversal:
Naive approach (broken for Unicode):
def is_palindrome(s):
return s == s[::-1] # Python slice reversal
s[::-1] reverses by Unicode code point, which breaks for strings containing combining characters, emoji sequences, or supplementary plane characters (above U+FFFF in Python 2 with narrow builds).
Correct approach requires grapheme cluster reversal:
import regex # Third-party 'regex' module, not 're'
def grapheme_clusters(s):
return regex.findall(r'\X', s) # \X matches one grapheme cluster
def is_palindrome_unicode(s):
clusters = grapheme_clusters(s)
return clusters == clusters[::-1]
The \X regex pattern matches one "grapheme cluster" — the human-perceived unit of a character (a base character plus any combining characters or emoji modifiers) — rather than one code point.
Text reversal in encodings: a historical footnote
Before Unicode, different character encodings handled bidirectional text differently, often incorrectly. The visual-vs-logical storage of Arabic and Hebrew text was inconsistently implemented across systems, leading to "visual encoding" (storing characters in display order, left-to-right, as they appear on screen) vs "logical encoding" (storing characters in reading order, right-to-left for Arabic/Hebrew, relying on rendering to flip display).
Unicode standardises on logical order: Arabic and Hebrew are stored in their natural reading order (the order they're typed), with the rendering engine responsible for display order via the UBA. This was a deliberate design choice that enables correct copy-paste, search, and cursor movement behaviours — but it means that applications must implement the UBA correctly, which many historically didn't.
How to use the Text Reverser on sadiqbd.com
- For ASCII and simple Latin text: the reversal tool correctly handles all standard ASCII and Latin-extended characters, including by character, by word, and by line
- For Unicode-aware needs: if working with emoji sequences, combined characters, or scripts with modifiers, verify the tool handles grapheme clusters rather than code points — test with a sequence like "👨👩👧" and check whether it reverses as a unit or breaks into component emoji
- For the "mirror text" effect: tools that produce mirror-image text for artistic use are doing something different from text reversal — they're replacing each character with its Unicode mirror image (where one exists) or using bidi control characters to achieve right-to-left display of normally left-to-right characters
Frequently Asked Questions
Why does copying reversed Arabic text and pasting it somewhere else sometimes produce different text than what was displayed? Because the bidirectional rendering algorithm operates at display time, not storage time. What's stored in memory (and therefore copied) is the logical sequence of Unicode code points in their natural language order. What you see on screen is the visual rendering, which may differ from the logical order for right-to-left scripts. When you copy and paste, you copy the logical order — which, when pasted into a different context with different paragraph direction or different bidi handling, may render differently. This is one of the fundamental complexities of working with bidi text: what you see is not always what is stored.
Is the Text Reverser free? Yes — completely free, no sign-up required.
Try the Text Reverser free at sadiqbd.com — reverse text by character, word, or line with Unicode support.