Zerowidth CleanerAll measured guides

CLAUDE WATERMARK REMOVER · PRACTICAL TEST

Why does a Unicode decimal-digit regex pass while Number returns NaN?

Our Arabic-Indic and Devanagari digit strings pass the Unicode Decimal_Number regex but still produce NaN with Number. The u flag does not make JavaScript digit shorthand accept them, and NFKC leaves these tested digits unchanged.

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

Open the Claude text cleaner · Full measured data

Code-point comparison for Marked Arabic Indic

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 Arabic Indic
direct string / keep / invisible true
"١​٢"
U+0661 U+200B U+0662
"١٢"
Removed 1 invisible character
{"asciiDigits":false,"unicodeDecimal":false,"number":"NaN","nfkc":"١​٢"}
{"asciiDigits":false,"unicodeDecimal":true,"number":"NaN","nfkc":"١٢"}
Arabic Indic
direct string / keep / invisible true
"١٢"
U+0661 U+0662
"١٢"
No selected invisible characters found
{"asciiDigits":false,"unicodeDecimal":true,"number":"NaN","nfkc":"١٢"}
{"asciiDigits":false,"unicodeDecimal":true,"number":"NaN","nfkc":"١٢"}
Devanagari
direct string / keep / invisible true
"१२"
U+0967 U+0968
"१२"
No selected invisible characters found
{"asciiDigits":false,"unicodeDecimal":true,"number":"NaN","nfkc":"१२"}
{"asciiDigits":false,"unicodeDecimal":true,"number":"NaN","nfkc":"१२"}
ASCII reference
direct string / keep / invisible true
"12"
U+0031 U+0032
"12"
No selected invisible characters found
{"asciiDigits":true,"unicodeDecimal":true,"number":"12","nfkc":"12"}
{"asciiDigits":true,"unicodeDecimal":true,"number":"12","nfkc":"12"}

A repaired character sequence can pass only one stage

The marked Arabic-Indic input contains one, U+200B and two. Initially both regex checks fail and Number yields NaN. After selected deletion, the Decimal_Number expression accepts the entire string, but the ASCII digit shorthand still rejects it and Number remains NaN. The observed change is classification acceptance, not numeric conversion. We record both booleans beside the numeric result so an application cannot mistake a successful Unicode-property check for a parsed quantity. The digit values are not converted to ASCII by the cleaner, whose callback only removes the configured marker from this authored sequence.

Two numeral systems and an ASCII reference

Unmarked Arabic-Indic ١٢ reproduces the same disagreement without cleanup. Devanagari १२ also passes the Unicode decimal property and fails both the shorthand check and Number conversion. ASCII 12 passes all three operations. The NFC/NFKC question is kept concrete: the observer’s NFKC field retains each tested Arabic-Indic and Devanagari string, so compatibility normalization does not supply the missing parser here. This differs from our fullwidth-digit experiment, where NFKC produces ASCII. We do not generalize either behavior to every numeric symbol, superscript, fraction or digit sequence represented anywhere in Unicode.

Use a parser that matches the promised input language

If a form promises support for a particular numeral system, pair its classification rule with an explicit, tested conversion policy for that system. If it only accepts ASCII decimal syntax, state that clearly and offer an actionable error. Do not strip legitimate digits because an unrelated hidden-character cleaner reports no findings. Keep the original source and validate the complete result, including the allowed range and any sign or separator rules. Our observer contains no locale-number parser or automatic digit mapping. It deliberately exposes the gap between two acceptance stages instead of manufacturing a numeric answer after the regex succeeds.

Property membership is not a semantic guarantee

All expressions are anchored and use the recorded JavaScript runtime. The shorthand expression also has u enabled, eliminating a missing flag as the explanation for this result. A Decimal_Number match establishes membership in that selected property for each supplied character; it does not establish intended quantity, business validity or accepted syntax in a destination service. We submit nothing to a browser form or remote API. These examples are authored test strings, not captured Claude output. Their purpose is to prevent a misleading success signal in a cleanup-and-import pipeline, with no inference about authorship, search demand, AI detection or watermark removal.

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 CharacterClassEscape 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.