Fix Weird Characters From Copy-Paste (’ Mojibake)

You paste a sentence from Word, Google Docs, or an AI chatbot into your code editor, CSV file, or web page, and suddenly an apostrophe becomes ’, a quote becomes “, and a space turns into Â. The text looked perfect a second ago. Nothing is corrupted and nothing is random: you are looking at mojibake, the predictable result of one program writing text as UTF-8 and another reading those same bytes as Windows-1252 (a legacy 8-bit Latin encoding). This guide decodes the exact sequences, explains the root cause, and walks through cleaning the text up.

The tell-tale sequences and what they really are

Almost every garbled punctuation mark you will see starts with â€. That is the signature of a UTF-8 multibyte sequence being misread one byte at a time. In UTF-8, characters above the basic ASCII range are encoded as two, three, or four bytes. The "smart" punctuation that word processors insert lives in the U+2000 range, which encodes to three bytes starting with E2 80. When a tool decodes each of those bytes as a separate Windows-1252 character, E2 renders as â (a-circumflex), 80 renders as the euro sign, and the third byte varies. Here are the common offenders:

Original characterCode pointUTF-8 bytesMojibake you see
Curly apostrophe / right single quoteU+2019E2 80 99’
Left double quoteU+201CE2 80 9C“
Right double quoteU+201DE2 80 9D†+ box
Em dashU+2014E2 80 94â€"
En dashU+2013E2 80 93â€"
EllipsisU+2026E2 80 A6…
No-break space (NBSP)U+00A0C2 A0Â + space

NBSP is the odd one out: it is a two-byte sequence C2 A0, so it shows up as a lone  followed by what looks like a normal space. If you see stray  characters sprinkled before spaces, currency symbols, or degree signs, that is the same encoding clash applied to the Latin-1 Supplement block (U+0080-U+00FF), where the lead byte is C2 or C3 instead of E2.

Why your document produced these characters at all

The root cause is two separate decisions stacking up. First, autoformat. Word and Google Docs ship with "smart quotes" turned on, which silently swaps your straight typewriter quote ' for the curly U+2019, your " for U+201C/U+201D, and a double hyphen for an em dash. AI writing tools do the same thing in their output because they are trained on professionally typeset prose. These characters are completely correct and look great in a finished article.

Second, the encoding mismatch. The smart characters are stored and copied as valid UTF-8. The corruption only appears when something downstream assumes the bytes are Windows-1252, or when the bytes get re-encoded twice. A CSV opened in a spreadsheet that defaults to a legacy code page, a database column declared as latin1, a script that reads a file without specifying encoding="utf-8", or an HTTP response missing charset=utf-8 in its Content-Type header will all trigger it. Per the WHATWG Encoding Standard, browsers even treat a declared ISO-8859-1 as Windows-1252, which is why these two encodings are effectively interchangeable in this failure mode.

Step 1: Identify the exact code point you have

Before you fix anything, confirm what you are actually holding. Two different problems look similar in a terminal: you might have a genuine curly quote (U+2019) that you simply want to normalize, or you might have already-corrupted mojibake bytes (’) that need to be re-decoded. The fix differs. Paste the suspect text into the Unicode character inspector and read it character by character. It shows the code point, the UTF-8 and UTF-16 bytes, the Unicode category, and the block for every character, so you can tell U+2019 (curly) from U+0027 (straight) at a glance, and spot whether â is a real U+00E2 or part of a misdecoded sequence.

The rule of thumb: if the inspector shows one code point in the U+2000 range, you have a normal smart character and just need to normalize it. If it shows the literal characters â, , and as three separate code points where a single apostrophe belongs, the bytes were already mangled and you need to re-read the file as UTF-8 at the source rather than search-and-replace.

Step 2: Normalize the punctuation to ASCII-safe equivalents

Once you confirm you have legitimate smart characters, convert them to their plain ASCII counterparts. The smart quotes converter (Straighten mode) turns curly quotes back into straight quotes, em and en dashes into hyphens, and ellipses into three dots, all in the browser without uploading anything. This is exactly the cleanup you want for code identifiers, JSON string values, CSV cells, and filenames, where a curly apostrophe is not interchangeable with a straight one. A few specifics worth knowing:

  • Curly to straight quotes: U+2019 becomes ' and U+201C/U+201D become ". Critical for JSON, because a JSON string must be delimited by straight U+0022 quotes per RFC 8259, and a curly quote inside source code is a syntax error in most languages.
  • Dashes to hyphens: the em dash U+2014 becomes a double hyphen -- and the en dash U+2013 becomes a single hyphen -. Either one read inside a CSV column or a slug looks like garbage in legacy tooling.
  • NBSP needs a manual sweep: the converter handles quotes, dashes, and ellipses, but a no-break space (U+00A0) survives it. NBSP is the sneaky one because it is invisible. Use the inspector to confirm where it is, then do a targeted find-and-replace of U+00A0 with a regular U+0020 space. An NBSP in a CSV header breaks column matching, and in a filename it produces names that look identical but will not match a script's string comparison.

Step 3: Hunt down the invisible characters AI text smuggles in

Mojibake is at least visible. The harder class of corruption is characters with no glyph at all. AI-generated and copy-pasted text frequently carries zero-width spaces (U+200B), zero-width joiners (U+200D), a byte-order mark (U+FEFF) at the start of a file, or directional formatting marks. They render as nothing, so the text looks clean, yet a string-length check disagrees with what you can see, an exact-match lookup silently fails, or a JSON parser chokes on a leading BOM. Run the text through the zero-width character detector to find these by position with their hex codes and strip them out. A BOM in particular will break the first key of a JSON file or add a phantom first column to a CSV, and it is impossible to see by eye.

Why it matters: fine in prose, fatal in data

None of these characters are wrong in an article. The problem is that prose and structured data have different rules. A curly apostrophe is invisible to a reader but is a different code point to a parser, so it breaks JSON.parse, confuses CSV field matching, produces filenames that will not match on disk, and shows up as ’ the moment the bytes cross an encoding boundary. The durable fix is to always read and write files as UTF-8 and declare charset=utf-8 on every HTTP response, then normalize punctuation and strip invisibles before text ever enters code, a database, or a data file. For the deeper mechanics of how UTF-8 actually encodes these code points into bytes, see our guide on what UTF-8 is and how it works.

Frequently Asked Questions

Word's autoformat replaced your straight apostrophe with a curly one (U+2019), which UTF-8 encodes as the bytes E2 80 99. Something downstream read those three bytes as separate Windows-1252 characters, producing ’. The text is not corrupted; an encoding mismatch is displaying valid UTF-8 as legacy Latin-1.

That  is a misread no-break space (U+00A0), which UTF-8 stores as the two bytes C2 A0. When read as Windows-1252, byte C2 renders as  and A0 renders as a space. The same C2/C3 lead byte produces stray  marks before currency symbols, degree signs, and other Latin-1 Supplement characters.

Paste the text into a Unicode inspector and read it character by character. One code point in the U+2000 range means you have a legitimate smart character to normalize. Three separate code points (â, €, ™) where one apostrophe belongs means the bytes were already mangled, so fix the encoding at the source instead of search-and-replacing.

Prose only needs to look right to a reader, but parsers compare exact code points. A curly apostrophe is a different code point from a straight one, so it breaks JSON.parse, which per RFC 8259 requires straight U+0022 quotes, confuses CSV field matching, and creates filenames that fail string comparison even though they look identical.

AI and pasted text often hide zero-width spaces (U+200B), joiners (U+200D), and a byte-order mark (U+FEFF). They render as nothing but break length checks, lookups, and JSON parsing. Run the text through a zero-width character detector to find each one by position with its hex code, then strip them before the text enters code or data files.