Zerowidth CleanerAll measured guides

CLAUDE WATERMARK REMOVER · PRACTICAL TEST

Why does Intl.NumberFormat show 2,500% for a cleaned value of 25?

Our en-US percent formatter displays 0.25 as 25% and 25 as 2,500%. The literal text 25% converts to NaN in this test. Cleanup repairs the marked fraction but does not choose whether your field stores ratios or percentage points.

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

Open the Claude text cleaner · Full measured data

Code-point comparison for Marked fraction

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 fraction
direct string / keep / invisible true
"0.2​5"
U+0030 U+002E U+0032 U+200B U+0035
"0.25"
Removed 1 invisible character
{"numberLabel":"NaN","finite":false,"display":"NaN%","parts":[{"type":"nan","value":"NaN"},{"type":"percentSign","value":"%"}]}
{"numberLabel":"0.25","finite":true,"display":"25%","parts":[{"type":"integer","value":"25"},{"type":"percentSign","value":"%"}]}
Fraction
direct string / keep / invisible true
"0.25"
U+0030 U+002E U+0032 U+0035
"0.25"
No selected invisible characters found
{"numberLabel":"0.25","finite":true,"display":"25%","parts":[{"type":"integer","value":"25"},{"type":"percentSign","value":"%"}]}
{"numberLabel":"0.25","finite":true,"display":"25%","parts":[{"type":"integer","value":"25"},{"type":"percentSign","value":"%"}]}
Whole percent-looking value
direct string / keep / invisible true
"25"
U+0032 U+0035
"25"
No selected invisible characters found
{"numberLabel":"25","finite":true,"display":"2,500%","parts":[{"type":"integer","value":"2"},{"type":"group","value":","},{"type":"integer","value":"500"},{"type":"percentSign","value":"%"}]}
{"numberLabel":"25","finite":true,"display":"2,500%","parts":[{"type":"integer","value":"2"},{"type":"group","value":","},{"type":"integer","value":"500"},{"type":"percentSign","value":"%"}]}
Percent suffix
direct string / keep / invisible true
"25%"
U+0032 U+0035 U+0025
"25%"
No selected invisible characters found
{"numberLabel":"NaN","finite":false,"display":"NaN%","parts":[{"type":"nan","value":"NaN"},{"type":"percentSign","value":"%"}]}
{"numberLabel":"NaN","finite":false,"display":"NaN%","parts":[{"type":"nan","value":"NaN"},{"type":"percentSign","value":"%"}]}

Two finite numeric inputs represent different scales

The marked input places U+200B between the two and five in 0.25. Number conversion is NaN before deletion, and the percent formatter displays NaN%. After deletion, conversion produces the finite ratio 0.25 and the display becomes 25%. The plain 0.25 control agrees with that final display without a cleanup event. The 25 control is also a finite number but formats as 2,500%, including the English grouping separator. We record numeric labels, finiteness and formatToParts output so the factor-of-one-hundred display difference is not hidden by a generic successful-format flag. The source of that difference is the supplied numeric scale rather than an extra digit inserted by the cleaner.

A written percent suffix is not parsed by this formatter path

The 25% text control is passed through Number first, which yields NaN; the observer then formats that NaN value. It does not invoke a percentage-text parser or strip the suffix. This unchanged control shows why a human-readable percentage label and the numeric input expected by a formatter are different representations. Earlier pages discuss localized decimal formatting and parsing the display back through Number. Here the locale is fixed and the question is which numeric unit enters percent formatting in the first place. We test four small authored strings, no financial instrument, performance return, statistical dashboard or measured business data. Runtime internationalization metadata is retained with the public evidence.

Define ratios and percentage points at the field boundary

Document whether the field stores a ratio such as 0.25 or a percentage-point quantity such as 25 before selecting its display path. If the latter is the intended data contract, perform any required conversion deliberately and verify it with a known reference; the cleaner cannot infer the unit from the digits. Check type and finiteness separately from a formatter returning text. Retain the original suffix-bearing value when the application accepts human-entered percentage notation and use its own defined parser. Our matrix supplies reproducible controls for scale confusion without choosing a universal input convention. A repaired numeric spelling and a plausible percent label provide no evidence about authorship or removal of a statistical watermark.

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

ECMA-402 number formatting 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.