Zerowidth CleanerAll measured guides

CLAUDE WATERMARK REMOVER · PRACTICAL TEST

Why does a cleaned 1_000 still convert to NaN?

An underscore accepted in a JavaScript numeric literal is not accepted by Number when it appears inside our string. Cleaning repairs the U+200B control but leaves 1_000 and 1,000 unchanged. Define a text-input grammar before conversion.

Tested October 20, 2026 · v24.19.0 · 4 measured runs

Open the Claude text cleaner · Full measured data

Code-point comparison for Marked digits

Measured inputs and outputs

These are locally constructed test strings, not evidence that Claude inserts these characters. We executed the saved homepage script snapshot with a minimal DOM harness and compared exact strings. The invisible-checkbox state and dash mode appear in each row. The observations below test this page's specific question. Destination observations run independently on the exact input and cleaned strings in the recorded Node runtime. We make no detector-score or statistical-watermark removal claim.

Before and after observations; full code points and strings are in the JSON download.
Fixture and modeInput string and code pointsOutput and cleaner statusObserved before / after
Marked digits
direct string / keep / invisible true
"1​000"
U+0031 U+200B U+0030 U+0030 U+0030
"1000"
Removed 1 invisible character
{"number":"NaN","decimalPrefix":"1","finite":false}
{"number":"1000","decimalPrefix":"1000","finite":true}
Underscore separator
direct string / keep / invisible true
"1_000"
U+0031 U+005F U+0030 U+0030 U+0030
"1_000"
No selected invisible characters found
{"number":"NaN","decimalPrefix":"1","finite":false}
{"number":"NaN","decimalPrefix":"1","finite":false}
Comma separator
direct string / keep / invisible true
"1,000"
U+0031 U+002C U+0030 U+0030 U+0030
"1,000"
No selected invisible characters found
{"number":"NaN","decimalPrefix":"1","finite":false}
{"number":"NaN","decimalPrefix":"1","finite":false}
Plain digits
direct string / keep / invisible true
"1000"
U+0031 U+0030 U+0030 U+0030
"1000"
No selected invisible characters found
{"number":"1000","decimalPrefix":"1000","finite":true}
{"number":"1000","decimalPrefix":"1000","finite":true}

A repair and two retained separators

The marked digits become 1000 and then convert to the number one thousand. By contrast, the underscore and comma controls retain their exact spelling and Number returns NaN before and after cleaning. The plain 1000 control already converts successfully. These four cases distinguish an actual selected marker from visible punctuation that a reader may consider grouping. The cleaner has no rule that translates all visually grouped quantities into a canonical number. A successful repair for the first string gives no evidence that the next two represent the same accepted input language.

Literal syntax does not transfer into the string

A programmer may write an underscore between digits in source code and expect that familiar notation to work in pasted data. Our observer deliberately passes a string to Number instead of evaluating source code. That distinction is the question tested here. The experiment does not use eval or compile the pasted field. The relevant ECMAScript definitions distinguish numeric source literals from string numeric conversion. We retain both the exact spelling and the conversion label so an underscore in the supplied data cannot be confused with formatting applied only to the displayed test result.

A decimal prefix can hide the remaining problem

For both 1_000 and 1,000, parseInt with radix ten returns one. It also returns one for the original marked input before cleanup. That shared prefix result is not a successful conversion of the intended grouped quantity. The repaired and plain controls return one thousand. The side-by-side observations show why replacing Number with a prefix parser is not a general separator fix. Define allowed signs, digits, grouping and fractional syntax in the application, validate the whole field, and only then convert the approved representation. Keep a rejected source value available for correction rather than silently accepting its first digit.

Boundaries for real imported data

These measurements cover the four exact strings in JavaScript and no locale-specific number parser, spreadsheet cell, database column or accounting workflow. Removing punctuation without knowing its role can change a decimal or list into a different quantity. We do not recommend deleting all underscores or commas from arbitrary text. A destination may intentionally accept a documented grouping convention and should validate that convention itself. Our conclusion concerns the mismatch between source-code notation and runtime text conversion, not whether a displayed quantity is financially or scientifically correct. The test is synthetic, reproducible and unrelated to any detector score.

Reproduce this test

Save reproduce.cjs and tested-app.js in the same folder. Run the command below with Node.js. The harness prints its runtime, script SHA-256 and every measured row. Compare those rows with the original record. Using a newer script or runtime creates a new experiment; retain the version information with your rerun.

node reproduce.cjs

Reference and next check

ECMAScript StringToNumber provides the relevant primary definition. The table and fixture analysis are original measurements. For broader inspection, use our Unicode inspector. Read the scope distinction before interpreting cleanup as a watermark result.