CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Why do capture groups disappear when I add g to match?
In our tests, match without g returns one match plus captures; match with g returns whole matches only. Use matchAll for per-match captures. Cleaning can restore a token, but cannot choose the result structure for you.
Open the Claude text cleaner · Full measured data
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.
| Fixture and mode | Input string and code points | Output and cleaner status | Observed before / after |
|---|---|---|---|
| Marked pair direct string / keep / invisible true | "A1 B2"U+0041 U+200B U+0031 U+0020 U+0042 U+0032 | "A1 B2"Removed 1 invisible character | {"single":["B2","B","2"],"global":["B2"],"all":[{"whole":"B2","letter":"B","digit":"2","index":4}]}{"single":["A1","A","1"],"global":["A1","B2"],"all":[{"whole":"A1","letter":"A","digit":"1","index":0},{"whole":"B2","letter":"B","digit":"2","index":3}]} |
| Plain pairs direct string / keep / invisible true | "A1 B2"U+0041 U+0031 U+0020 U+0042 U+0032 | "A1 B2"No selected invisible characters found | {"single":["A1","A","1"],"global":["A1","B2"],"all":[{"whole":"A1","letter":"A","digit":"1","index":0},{"whole":"B2","letter":"B","digit":"2","index":3}]}{"single":["A1","A","1"],"global":["A1","B2"],"all":[{"whole":"A1","letter":"A","digit":"1","index":0},{"whole":"B2","letter":"B","digit":"2","index":3}]} |
| One pair direct string / keep / invisible true | "A1"U+0041 U+0031 | "A1"No selected invisible characters found | {"single":["A1","A","1"],"global":["A1"],"all":[{"whole":"A1","letter":"A","digit":"1","index":0}]}{"single":["A1","A","1"],"global":["A1"],"all":[{"whole":"A1","letter":"A","digit":"1","index":0}]} |
| No pair direct string / keep / invisible true | "AA"U+0041 U+0041 | "AA"No selected invisible characters found | {"single":null,"global":null,"all":[]}{"single":null,"global":null,"all":[]} |
Two operations return different array meanings
Our observer uses the same letter-and-digit pattern with and without the global flag. For plain A1 B2, the non-global result contains A1, A and 1. Its global counterpart contains A1 and B2. Index one consequently represents a captured letter in the first array and the second whole match in the other. Reading that position with an unchanged assumption can silently produce the wrong field. This problem exists in the plain control and does not require any invisible character. The data shows the arrays themselves instead of summarizing both as successful regex matches.
Cleanup changes token recognition independently
The marked fixture separates A from 1 with U+200B. Before cleaning, only B2 matches. After deletion, both A1 and B2 qualify. That change occurs alongside the result-shape distinction, so a comparison must examine both membership and structure. Our matchAll observer records whole text, letter, digit and index for every result. For the no-pair control, match returns null in both modes while matchAll produces an empty collected list. Code that assumes an array must handle that null case explicitly. The table retains those outcomes rather than converting every absence into one common value.
Select a stable extraction contract
When extracting multiple captured fields, collect each matchAll result and select named or numbered captures deliberately. When only whole occurrences matter, the global match array may be sufficient. For a single match with groups, handle a non-global null result before reading a capture. Test these choices with a two-occurrence control so accidentally reading the second occurrence as a group becomes visible. Our one-pair control helps isolate the issue from the number of tokens. Recompute the extraction after an approved edit; the cleaner does not update a previously stored result array or its indices.
Limits of this lexical example
The authored pattern recognizes only the simple ASCII label shape shown in the reproducer. It is not a schema for all identifiers or a linguistic tokenization model. We do not run it inside an editor, browser extension or code compiler, and do not infer those applications use the same extraction method. The measurements demonstrate global match array semantics using the saved runtime. The earlier matchAll article remains the companion for offset movement; this page addresses what an array element means. No fixture is a captured Claude response or evidence that deleting characters affects any model-level 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.cjsReference and next check
ECMAScript RegExp match 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.