Regex Grapheme Cluster In Class

ID

java.regex_grapheme_cluster_in_class

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Java

Tags

code-style

Description

Reports a regex character class that combines a base character with a following Unicode combining mark — visually one grapheme, encoded as two separate class members.

Rationale

Some visible characters are not a single Unicode code point. ö, for instance, is the letter o followed by the combining diaeresis U+0308; it looks like one character on screen but is two in the source.

A character class is an enumeration of its members, never a sequence, so writing that pair inside […​] does not name the combined grapheme — it names two independent alternatives, the base letter or the bare mark:

"nöñn".replaceAll("[öñ]", "X");
// intent: replace the accented "ö" and "ñ"
// actual: [öñ] enumerates {o, ̈, n, ̃}, so every plain 'o', every plain 'n'
//         and every bare combining mark is replaced too

Remediation

Use an alternation instead of a class — ö|ñ matches the two-code-point grapheme as a unit, the way the class was meant to:

"nöñn".replaceAll("ö|ñ", "X");

What is not reported

A base+mark pair outside a character class — for example already written as an alternation — is the documented fix and is never reported. A mark spelled out as an explicit escape, whether a four-hex-digit Unicode code-point escape (backslash, u, 0308) or a named escape (\N{COMBINING DIAERESIS}), is treated as a deliberate, individually-enumerated code point rather than an accidental grapheme, and is not reported either. A run of marks with no base character in front of them, or a class holding a single character on its own, is not a cluster.

© 2026 Xygeni. All rights reserved