Free string reverser with all three readings
Reverse a string three ways at once
Paste one line and TextLab reverses it three different ways at the same time: by visible character, by Unicode code point and by UTF-16 code unit. It is free, takes no signup, and the three answers are shown side by side because they are genuinely different — plain ASCII makes them agree, and one emoji makes them disagree loudly. A table underneath lists every code point in your string so you can see exactly which pieces the last two readings are pulling apart.
- 100% free
- No signup
- Three readings compared
- Code point table
- Palindrome check
By visible character
0 charactersGrapheme clusters, the units a reader counts. An emoji, a flag and a letter with an accent each move as one.
By code point
0 code pointsWhat [...s].reverse() gives you. Surrogate pairs survive, but joiners and accents come loose from what they were attached to.
By UTF-16 code unit
0 code unitsWhat s.split("").reverse().join("") gives you. Every character above U+FFFF is split down the middle and renders as two replacement marks.
How to reverse a string
One line in, three reversals out, and a table explaining why they differ.
Drop one line into the field
This page works on a single string at a time, so the field holds one line and a paste with line breaks in it arrives with those breaks turned into spaces. Use the sample chips underneath to load a family emoji, a flag, a skin-tone modifier or a decomposed accent if you want to watch the three readings pull apart on something known.
Compare the three answers
The first panel reverses by visible character and is the one to use for anything a person will read. The second reverses by code point, which is what a spread operator or a for-of loop gives you. The third reverses by UTF-16 code unit, the answer the classic split-reverse-join one-liner produces. When your string is plain ASCII all three agree, and the strip underneath says so.
Read the table to see why they differ
Every code point in the string is listed with its U+ number, how many UTF-16 slots it fills and which visible character it belongs to. Rows sharing a number in the last column are one character on screen — those groups are exactly what the first reading protects and the other two break apart. The palindrome verdict above the table compares the string with its own reversal after normalising it, with folding of case and punctuation as options.
Technical specifications
| Reversals shown | Three at once: by visible character (grapheme cluster), by Unicode code point, and by UTF-16 code unit |
|---|---|
| How the visible characters are found | Intl.Segmenter with grapheme granularity, following Unicode Annex #29; browsers without it fall back to a hand-rolled grouping of marks, joiners, regional-indicator pairs and keycaps |
| Input | One line at a time; line breaks in a paste become spaces, and there is no length cap beyond what the field can hold |
| Code point table | The first 120 code points, each with its U+ number, its UTF-16 width of 1 or 2, and the number of the visible character it belongs to; the zero-width joiner, zero-width space, no-break space, tab, both variation selectors and the combining keycap are named rather than drawn as empty cells |
| Palindrome test | Compares the string with its grapheme reversal after NFC normalisation, with optional folding of capitals and of every character that is neither a letter nor a digit |
| Worked example | The four-person family emoji is 7 code points and 11 UTF-16 units; a two-letter flag is 2 and 4; a skin-toned thumbs-up is 2 and 4; a decomposed é is 2 and 2 |
| Speed and privacy | A 1,000-character line is segmented and reversed three ways in under 1 ms, all of it inside this tab with no request to a server |
| Price | Free. No account, no metering, and the hundredth string costs exactly what the first one did |
Frequently asked questions
Why does my reversed string come back full of question marks?
Because the reversal cut characters in half. Anything above U+FFFF — every emoji, every musical symbol, most historic scripts — is stored as two UTF-16 units that are only meaningful in that order, called a surrogate pair. Reversing unit by unit puts the second half first, and each orphaned half is not a valid character at all, so the font draws the replacement mark instead. The third panel above shows this happening deliberately, and the first shows the same string reversed without it.
Which of the three reversals should I actually use?
Use the first one, by visible character, unless you have a specific reason not to. It is the only reading that matches what a person sees, so it is right for display text, for puzzles and for anything a user will read back. The code point reading is defensible for fixed-width analysis where combining marks are known to be absent. The UTF-16 reading is almost never what anyone wants and survives only because it is the shortest to type — it is the reversal that produces the bug reports.
Does reversing a string change its length?
Not if you reverse it properly: the same characters come back in the opposite order, so all three counts above are identical before and after. A careless reversal can change the byte length, though. Split a surrogate pair and the orphaned halves cannot be encoded in UTF-8 at all; encoders substitute the replacement character, which costs three bytes each, so a four-byte emoji comes out as six bytes of nothing useful. That is the mechanism behind reversal bugs that only show up after the text is saved to a file or sent over a network.
Why does split, reverse and join not work?
Because splitting on an empty string cuts at every UTF-16 unit rather than at every character. JavaScript strings were designed in 1995 around a 16-bit character set that everyone expected to be enough, and the language kept that model when Unicode outgrew it — so the length property, indexing and split all count storage slots rather than characters. On plain English text a slot and a character are the same thing, which is why the one-liner passes every test written in ASCII and fails the first time somebody types an emoji.
Do accents end up on the wrong letter?
They do under the naive reversals, and this is the failure that hides best because nothing renders as a broken box. A combining accent attaches to whatever character precedes it, so in a decomposed string the é in café is stored as e followed by the accent. Reverse the pieces and the accent now trails the f, giving f́ac and a bare e at the end. Normalising to NFC first hides the problem for the couple of hundred letters that have a precomposed form, but it cannot help Vietnamese or Thai, where stacked marks routinely have no single-code-point equivalent. Grouping by visible character does.
What happens if I reverse Arabic or Hebrew?
You get the characters in the opposite logical order, which is probably not what you saw on screen. Right-to-left text is stored in reading order and laid out backwards by the browser's bidirectional algorithm at display time, so reversing the stored order and then letting the browser reverse it again for display can leave a line looking oddly familiar while being genuinely reversed underneath. Mixed text is worse: an English phrase inside an Arabic sentence has its own direction, and reversal shuffles the boundaries between the two runs.
How does the palindrome check decide?
It compares the string with its own visible-character reversal, after normalising to NFC so that a typed é and an e with a separate accent count as the same letter. Two switches control the rest: ignoring capitals, and ignoring every character that is neither a letter nor a digit, which is what turns "A man, a plan, a canal: Panama" into a palindrome. Left strict, the same phrase is not one — punctuation and spaces are characters too, and a palindrome test that silently drops them is answering a different question from the one you asked.
Why your reversed string is broken
There is no single correct way to reverse a string, because there is no single unit that a string is made of. There are three, and they are nested inside each other. The smallest is the UTF-16 code unit, a 16-bit slot; next is the code point, a number Unicode has assigned a meaning to, which needs either one slot or two; largest is the grapheme cluster, one or more code points that a reader sees as a single character. For the ASCII range all three are the same thing, which is why the problem stayed invisible for so long and why it always surfaces in production rather than in tests.
The reason a language hands you the wrong one by default is historical. When JavaScript was designed in 1995, Unicode was a 16-bit character set and 65,536 slots looked generous, so strings were defined as sequences of 16-bit units and the length property counted them. Unicode outgrew that ceiling the following year, and everything above it — emoji, ancient scripts, mathematical alphabets, the newer CJK extensions — has since been encoded as a pair of units drawn from a reserved block, meaningful only together. The language could not change what length meant without breaking the web, so the model stayed. Reversing by code unit therefore does something with no defensible meaning at all: it swaps the halves of every surrogate pair, and the two orphans left behind are not characters, which is why they render as replacement marks and why an encoder writing them to a file has to throw them away. Reversing by code point fixes that and leaves two subtler faults, because a combining accent belongs to the character before it and a zero-width joiner welds the characters on either side of it — reverse them and the accent attaches itself to the wrong neighbour while a joined emoji scatters. Only the third reading, the grapheme cluster, matches what a reader would call a character; browsers expose it through Intl.Segmenter, and it is what the first panel above uses.
The practical advice is short: decide which unit you mean, rather than accepting the one your language reaches for first. Anything a person will read wants the visible character. A checksum or a fixture can use whichever unit it likes, provided it is written down. And a palindrome test needs normalising before it compares, or a decomposed é will fail to match a precomposed one that looks identical. If your interest is a passage rather than a single line — a poem read tail-first, or every word turned inside out — the reverse text page handles multi-line input with the same cluster-safe machinery, and reverse list flips the order of lines without touching a single character inside them. When the string turns out to be full of invisible passengers picked up from a copy and paste, the text cleaner will name and remove them.
Strings you would rather not send anywhere
People testing a reversal habitually paste whatever string is in front of them, and that is often a token, a licence key, a customer identifier or a fragment of a password. None of it moves: the segmentation, the three reversals, the code point table and the palindrome test are all worked out by the script that came down with this page, so there is no request to a server for anything you type, and nothing is stored or logged. Reload the tab and the field is empty again, with no history to clear.