TextReverse

Character Reverser

Reverse a string one character at a time, with the Unicode handling most reversers get wrong. Emoji and other astral characters move as single units instead of being torn into unpaired surrogates.

If you are testing a reverse function, debugging mojibake, or just need a reference implementation you can paste into, this page shows exactly what correct code-point reversal produces β€” including the cases where correct still is not perfect.

abcπŸ˜€deffedπŸ˜€cba

Working with words rather than characters? Reverse letters per word

0 characters0 words0 lines
Your transformed text will appear here...
0 characters0 words0 lines
Ctrl + Enter Copy resultEsc Clear

Character Reversal Test Cases

These double as a test suite. If your own reverse function disagrees with any row here, it is almost certainly splitting UTF-16 units instead of code points.

InputOutputWhat it shows
abcdeffedcbaBaseline: pure ASCII reverses trivially.
abπŸ˜€cddcπŸ˜€baThe emoji stays whole. A naive split("") produces two broken glyphs here.
π•Œπ•Ÿπ•šπ•”π• π••π•–π•–π••π• π•”π•šπ•Ÿπ•ŒAstral mathematical characters are each one code point and survive.
cafééfacA precomposed é reverses cleanly as a single character.
a b cc b aTabs and newlines are ordinary characters and reverse in place.
padded deddap Leading and trailing spaces swap ends rather than being trimmed.
12345678900987654321Digit strings reverse without any numeric interpretation.
<div class="x">>"x"=ssalc vid<Angle brackets and quotes are not escaped or altered.
ABCdef123!@##@!321fedCBAMixed classes confirm nothing is reordered by type.

Code Points, Units and Graphemes

There are three plausible answers to "what is a character", and picking the wrong one is why so many reverse functions corrupt text.

UTF-16 code units: the wrong choice

JavaScript strings are sequences of 16-bit units. text.split("").reverse().join("") reverses those units, which swaps the halves of any character outside the Basic Multilingual Plane. Every emoji in the string becomes two replacement glyphs.

Code points: what this tool uses

Array.from(text) iterates code points, so a surrogate pair is yielded as one two-unit string and moves as a unit. This is the correct default and fixes the entire emoji class of bugs.

Grapheme clusters: the perfect but heavier option

A user-perceived character can span several code points β€” a base letter plus combining marks, or emoji joined by zero-width joiners. Reversing grapheme clusters requires Intl.Segmenter and a much larger implementation; this tool works at code-point level and documents the difference rather than pretending it does not exist.

Why the distinction shows up in counts

The character counts on this page use code points too, so "πŸ˜€πŸ˜€" counts as 2 rather than the 4 that String.length reports. If your own counter disagrees with the tool, that is usually why.

Reversal Granularity Compared

Four levels at which a string can be reversed, applied to the same input. Choosing the granularity is the whole decision.

Shared input: abc def ghi jkl

TransformationResultReach for it when
Characterslkj ihg fed cbaYou want a true end-to-start string reversal.
Characters within wordscba fed ihg lkjYou want per-token reversal with layout preserved.
Wordsjkl ghi def abcYou want token order flipped, tokens intact.
Linesghi jkl abc defYou want record order flipped in a list or log.

Documented Reversal Behaviour

Each of these is covered by a unit test in the repository, so the behaviour is deliberate and will not drift.

Surrogate pairs stay intact

Reversing "abπŸ˜€cd" produces "dcπŸ˜€ba". The emoji is a single code point stored as two UTF-16 units, and it is never split. This is asserted directly in the test suite.

ZWJ sequences are separated

The family emoji πŸ‘¨β€πŸ‘©β€πŸ‘§ is three emoji plus two zero-width joiners. Code-point reversal yields the components in reverse order rather than the combined glyph. Documented limitation, not silent corruption.

Combining marks detach from their base

The decomposed form of Γ© is "e" followed by U+0301. After reversal the combining acute precedes the e and attaches to whatever now sits before it. The precomposed U+00E9 form has no such problem.

CRLF becomes LFCR

A Windows line ending is two characters. Reversing a document with CRLF endings puts the line feed before the carriage return. If you are reversing files rather than prose, normalise line endings first.

Notes for Developers

The behaviour above maps onto the equivalent operations in the languages people most often ask about.

JavaScript and TypeScript

Use Array.from(str).reverse().join(""), or [...str] which iterates the same way. Avoid str.split("") entirely. For grapheme-accurate reversal, segment with Intl.Segmenter("grapheme") first.

Python

str[::-1] reverses by code point already, because Python 3 strings are sequences of code points rather than UTF-16 units. Combining marks still detach, so the grapheme caveat applies there too.

Java and C#

Both use UTF-16 internally, so StringBuilder.reverse() and a naive char[] reversal have the same surrogate problem as JavaScript. Java's StringBuilder.reverse() does special-case surrogate pairs; a hand-rolled loop usually does not.

Go and Rust

Strings are UTF-8 byte sequences. Reversing bytes corrupts any multi-byte character, so iterate runes in Go or chars in Rust and reverse that sequence instead.

When You Need Character-Level Reversal

Testing your own implementation

Paste the emoji and accent rows from the table above into your function. Any difference from the outputs here points straight at a UTF-16 assumption in your code.

Building test fixtures

Reversed strings with mixed scripts make good fixtures for text pipelines, because they exercise encoding paths that plain ASCII never touches.

Interview practice

"Reverse a string" is a classic interview question, and the Unicode follow-up is the part that separates answers. The cases here are the ones worth being able to discuss.

Debugging mojibake

If reversed text renders as replacement characters somewhere in your stack, comparing against this output isolates whether the corruption happened at reversal or later.

Frequently Asked Questions

Related Text Tools

Browse all text tools β†’