Guides

How to Reverse a String in Python: Slicing, Words, and Unicode

A practical Python guide to reversing strings, word order, letters within words, and lines—with whitespace-preserving examples and Unicode fixes.

By Text Reverser TeamOctober 22, 20268 min read

To reverse a string in Python, use text[::-1]. This creates a new string in reverse code-point order and leaves the original unchanged. It is the right starting point for ordinary text, but reversing words, keeping whitespace, and handling emoji require different choices.

This guide shows the differences with runnable Python 3 examples, explains the common mistakes, and helps you choose a method that matches what you actually want to reverse. If you only need a quick one-off result, try the online text reverser instead of writing a script.

Quick answer: use a slice with a negative step

text = "Python is fun"
backwards = text[::-1]

print(backwards)  # nuf si nohtyP
print(text)       # Python is fun

The slice syntax is sequence[start:stop:step]. With [::-1], the start and stop are omitted and the step is negative one. Python walks through the string from its end toward its beginning, taking every item. You do not need to calculate the last index yourself.

Strings are immutable: you cannot change their individual positions in place. Assign the reversed result to a variable, return it from a function, or use it directly. Writing text[::-1] on its own does not replace the value stored in text.

The same expression handles an empty string and a one-character string without special branches:

assert ""[::-1] == ""
assert "A"[::-1] == "A"
assert "12345"[::-1] == "54321"

Python documents strings as immutable sequences of Unicode code points. That last phrase matters: a code point is not always the same thing as one visible character. We will return to that distinction below.

Choose the right kind of reversal

Several tasks are casually called “reverse text,” but they produce very different results. For the input Python is fun, decide which output you need before choosing code:

  • Reverse the entire string: nuf si nohtyP
  • Reverse word order: fun is Python
  • Reverse letters inside each word: nohtyP si nuf
  • Reverse a list of lines: move the last line first without reversing its spelling.

Whole-string slicing reverses spaces and punctuation along with letters. It is not a grammatical rewrite, and it does not mirror the shapes of letters. For example, "Hello!"[::-1] becomes !olleH, not a visually reflected image.

If you are comparing these transformations for the first time, our word-order reversal guide explains the non-programming version with more examples.

Alternative: join the output of reversed()

Python also provides the built-in reversed() function:

text = "Python is fun"
backwards = "".join(reversed(text))

print(backwards)  # nuf si nohtyP

According to the official reversed() documentation, the function returns a reverse iterator. It does not return a finished string. The empty-string separator in "".join(...) combines the items without putting anything between them.

Use slicing when you want a concise reversed string. Use reversed(text) when you want to process the items one at a time:

for character in reversed("cat"):
    print(character)
# t
# a
# c

Neither form automatically keeps combining marks or multi-code-point emoji together. Switching from slicing to reversed() changes the interface, not the underlying unit of reversal.

Reverse word order in a sentence

For a sentence where normalizing whitespace is acceptable, split the text into words, reverse the resulting list, and join it:

text = "Python is fun"
result = " ".join(text.split()[::-1])

print(result)  # fun is Python

Calling split() without an argument treats runs of whitespace as separators. This is convenient for an ordinary sentence, but it discards leading and trailing whitespace and collapses tabs, newlines, and repeated spaces when you join with a single space.

text = "  red  blue\tgreen  "
result = " ".join(text.split()[::-1])

print(repr(result))  # 'green blue red'

Punctuation stays attached to each token: Hello, world! becomes world! Hello,. This code treats a “word” as a whitespace-separated chunk, not a linguistic unit. It will not separate words in languages that normally omit spaces, and it will not move punctuation into grammatically natural positions.

Keep the whitespace slots while reversing words

If repeated spaces and tabs matter, preserve them separately. The following example reverses the non-whitespace chunks while leaving the whitespace runs in their original sequence:

import re

text = "red  blue\tgreen"
parts = re.split(r"(\s+)", text)
words = iter(re.findall(r"\S+", text)[::-1])

result = "".join(
    next(words) if part and not part.isspace() else part
    for part in parts
)

print(repr(result))  # 'green  blue\tred'

The capturing parentheses in re.split(r"(\s+)", text) retain the separators in the returned list, as described in the Python regular-expression documentation. The iterator supplies the reversed words only when the code reaches a word slot.

This preserves the whitespace runs, not fixed screen columns: a longer replacement word can still push the next column sideways. Newlines also count as whitespace here, so words may move across line boundaries. For a multi-line document, decide whether reversal should happen across the entire document or independently within each line.

Reverse letters inside each word without changing word order

Use substitution to reverse each non-whitespace chunk while keeping the separators untouched:

import re

text = "red  blue\tgreen"
result = re.sub(r"\S+", lambda match: match.group(0)[::-1], text)

print(repr(result))  # 'der  eulb\tneerg'

Unlike a simple split() followed by join(), this leaves repeated spaces, tabs, and newlines in place. It also reverses punctuation inside each chunk. For example, Hello, world! becomes ,olleH !dlrow.

If you need punctuation to remain at each word's edges, define that rule explicitly before changing the pattern. Apostrophes, hyphens, digits, and different writing systems make “letters only” more complicated than it first appears. For the conceptual distinction, see reversing letters while keeping word order.

Unicode: why accents and emoji can break

A Python string stores Unicode code points. A visible symbol may contain more than one: a letter followed by a combining accent, a flag made from regional indicators, or an emoji joined to another emoji. Reversing the code points can separate those pieces.

Consider an accented e written as two code points rather than one:

text = "e\u0301x"  # e + COMBINING ACUTE ACCENT + x

print([f"U+{ord(ch):04X}" for ch in text])
# ['U+0065', 'U+0301', 'U+0078']

print([f"U+{ord(ch):04X}" for ch in text[::-1]])
# ['U+0078', 'U+0301', 'U+0065']

After reversal, the accent follows x instead of e. The output may still display as plausible text, which makes this bug easy to miss. Looking only at what the terminal draws is not enough to establish that the sequence stayed intact.

Unicode defines extended grapheme clusters to approximate user-perceived characters. Reversing clusters instead of individual code points is usually a better choice when the goal is to keep visible character units together.

Reverse grapheme clusters with the regex package

The third-party regex package supports \X for grapheme matching. Install it into the Python environment running your script:

python -m pip install regex

Then split into clusters before reversing:

import regex

def reverse_graphemes(text):
    clusters = regex.findall(r"\X", text)
    return "".join(clusters[::-1])

assert reverse_graphemes("e\u0301x") == "xe\u0301"
assert reverse_graphemes("A👩‍💻B") == "B👩‍💻A"

The built-in re module and the separately installed regex package are different libraries. Do not replace import regex with import re and expect this pattern to work. See the package's Unicode grapheme-matching documentation for supported behavior and Python-version requirements.

Cluster reversal is still not a visual mirror operation. Right-to-left scripts and mixed-direction text have display rules beyond their stored order, and some language-specific character units need more tailored handling. Keep the package current and test representative text from the languages your application supports. Normalizing accents alone is not a universal fix for joined emoji or all writing systems.

Reverse the order of lines, not the characters

A list, poem, or small text file often needs its lines reordered rather than every character reversed. Use splitlines() to get the logical lines:

text = "first\nsecond\nthird\n"
lines = text.splitlines()
result = "\n".join(reversed(lines))

if text.endswith(("\n", "\r")):
    result += "\n"

print(repr(result))
# 'third\nsecond\nfirst\n'

This example intentionally standardizes the output separators to \n and retains a final newline when the input ends with LF or CR. It does not preserve mixed line-ending formats byte for byte. Python's splitlines() method also recognizes additional Unicode line boundaries; if those must remain exact, define and test a more specific line-ending policy.

Be careful with splitlines(keepends=True): reversing complete line chunks can join two lines accidentally if the original last line had no terminator. Separating content from the output separator makes the intended behavior easier to see.

For a small UTF-8 file, read the text explicitly and write to a different destination so you do not overwrite the original while experimenting. The examples above hold their data in memory; a very large file needs a separate storage and memory strategy.

Common mistakes and how to avoid them

Calling text.reverse()

Strings do not have a reverse() method. Lists do, but list.reverse() mutates the list and returns None. For a string result, use a slice or "".join(reversed(text)) instead.

Using sorted() instead of reversed()

sorted(text, reverse=True) sorts items into descending order; it does not preserve their original relative sequence backward. Sorting cat gives tca, while reversing it gives tac. These operations answer different questions.

Reversing encoded bytes

Do not encode Unicode text to UTF-8 and reverse the byte sequence as a shortcut. A single character can require multiple bytes; reversing them may create invalid UTF-8. Decode incoming text using the correct encoding, reverse at the code-point or grapheme level, then encode the result if necessary.

Treating reversal as security

Reversed text is easy to undo. It is useful for puzzles and demonstrations, not password protection, encryption, or hiding private information. Do not place secrets into an output simply because the letters appear backward.

Building the answer by repeated prepending

A loop that repeatedly does result = character + result looks simple, but it repeatedly constructs strings. Prefer slicing for the complete result, or collect pieces and join them. Avoid recursive reversal for ordinary application code: it adds complexity and can run into recursion limits.

Test the rules, not just one happy-path example

A reusable code-point reversal function can be very small:

def reverse_text(text):
    return text[::-1]

assert reverse_text("abc") == "cba"
assert reverse_text("") == ""
assert reverse_text("a b!") == "!b a"
assert reverse_text(reverse_text("a\tb\n")) == "a\tb\n"

For word-based transformations, add leading spaces, repeated spaces, tabs, punctuation, and blank input to your tests. For grapheme-aware code, include decomposed accents and joined emoji. The double-reversal check is useful for code-point reversal, but it does not prove that a single reversal looks correct to a reader.

If these functions accept user input, specify that the input must be a string. Silently converting None or a list with str(...) can hide an upstream mistake instead of fixing it.

Frequently asked questions

What is the simplest way to reverse a Python string?

Use text[::-1]. It is concise, requires no imports, and reverses the stored code-point order. For visible characters containing multiple code points, use grapheme-aware segmentation instead.

Does Python reverse the original string in place?

No. Strings are immutable. The expression returns a reversed string value; assign that value back to text if replacing your variable is intentional.

Can I reverse a string without slicing?

Yes: "".join(reversed(text)) creates the same code-point-reversed result. A loop over reversed(text) is useful when you want to handle items individually rather than create a complete string immediately.

Will these methods create mirror writing?

No. Reordering characters does not reflect their glyphs. For a visually mirrored print design, use a graphics or document tool that can flip the rendered text horizontally.

The practical rule

Start with text[::-1] for whole-string code-point reversal. Split and join when you want word order, preserve separators when formatting matters, and use grapheme clusters when accents and emoji must stay together. Choosing the right unit first prevents most surprising results—and keeps a simple text task simple.

Try the Text Reverser tool

Reverse text, words, or letters instantly — free and entirely in your browser.

Open the tool

Permalink: https://www.textreverser.me/blog/reverse-string-python