DEV Community

Cover image for Does Paste as Plain Text Remove Zero-Width Spaces?
Davis Scott
Davis Scott

Posted on

Does Paste as Plain Text Remove Zero-Width Spaces?

Two clipboards, two jobs

A modern copy puts more than one flavour on the clipboard.
text/html: spans, styles, data-message-* from a ChatGPT bubble select.
text/plain: the Unicode string, hidden characters included.

"Paste as plain text" means "please take text/plain." The destination throws away the HTML flavour. It does not run a Unicode allow-list. U+200B is a legal letter-like code point in that string. U+00A0 is a legal space. The OS is correct to keep them.

Wikimedia and others have noted that selecting a ChatGPT bubble can copy HTML bookkeeping (data-message-author-role, data-message-id). The Copy button is cleaner on that layer. Neither gesture promises a U+200B-free string. You can do everything right on HTML and still be dirty on Unicode.

What plain text actually strips

Usually gone: font-family, colour, heading styles, data-message-* attributes, most spans from the chat bubble, Docs comments, Word's mso- junk if you came through Office.

Still there: letters, punctuation, emoji, U+200B, U+200C, U+200D, U+00A0, U+202F, U+FEFF if it was in the string, and ordinary \n.

If your sanitizer is strip_tags, you have not sanitised U+200B. If your sanitizer is encode('ascii', 'ignore'), you have destroyed names and emoji. Target the code points.

Prove it in thirty seconds

Word's Keep Text Only path is the same experiment with more UI. Save as .txt after a Keep Text Only paste and inspect hex. The e2 80 8b UTF-8 sequence for U+200B will still be there if it was in the source.

const dirty = "pipe\u200Bline";
const el = document.createElement("textarea");
el.value = dirty; // this is what a "plain" paste into a form looks like
console.log([...el.value].map(c => c.codePointAt(0).toString(16)));
// still contains 200b

Enter fullscreen mode Exit fullscreen mode

Word's Keep Text Only path is the same experiment with more UI. Save as .txt after a Keep Text Only paste and inspect hex. The e2 80 8b UTF-8 sequence for U+200B will still be there if it was in the source.

Node, if you want a file:

import { writeFileSync } from "fs";
writeFileSync("out.txt", "pipe\u200Bline", "utf8");
// xxd out.txt  →  70 69 70 65 e2 80 8b 6c 69 6e 65

Enter fullscreen mode Exit fullscreen mode

textarea.value, .txt, JSON.stringify, and git diff all agree: plain text kept the character.

“What to run after plain-text paste.”

Strip the zero-width set, and replace no-break spaces with U+0020:

s.replace(/[\u200B\u200C\u200D\uFEFF]/g, "").replace(/[\u00A0\u202F]/g, " ")

Enter fullscreen mode Exit fullscreen mode

Python:

import re
s = re.sub(r"[\u200b\u200c\u200d\ufeff]", "", s)
s = re.sub(r"[\u00a0\u202f]", " ", s)
Enter fullscreen mode Exit fullscreen mode

Or paste into GPTCleanup, scan, and copy the character-clean version. You do not need an account for the Unicode-clean copy. Phrase humanization is paid and irrelevant to this bug.
If you only do the homepage scan and then paste rich into Word, you can pick up new HTML from whatever you copied in between. Scan, then paste as text, is the pair.

Why the myth exists

"Paste as plain text" fixed a generation of Word-to-CMS disasters caused by styles. People generalised it to "plain text means only the letters I can see." Unicode includes letters and a pile of format characters. Zero-width space is in the second pile. The myth is a category error, and it is sticky because the first layer (HTML) really does disappear, so the ritual feels complete.

A second source of the myth: some Windows Notepad builds used to drop or mangle certain controls when the encoding was ANSI. People remember "Notepad cleaned it." Modern Notepad on UTF-8 will keep U+200B. Do not rely on folklore from XP.

A third source: Google Docs "paste without formatting" is described in help articles as removing styles. Readers hear "formatting" and think "anything invisible." U+200B is content.

A pipeline that does both layers

Copy with the ChatGPT message Copy control (cuts a lot of HTML at the source).

Paste as plain text into a scratch buffer (kills remaining HTML).

Strip hidden Unicode (kills U+200B and friends).

Then parse JSON, paste into Word, or commit the fixture.

Skip 2 and you fight styles. Skip 3 and you fight ghosts. Do both and the ticket closes.

Top comments (0)