How Lodash Words Segments Compound Emoji Characters
The Lodash _.words utility accurately isolates words and
complex characters—including compound emojis—by combining Unicode
feature detection with an elaborate, purpose-built regular expression.
When processing strings, Lodash avoids standard naive character
splitting, instead recognizing multi-codepoint sequences such as
Zero-Width Joiners, variation selectors, and skin tone modifiers. This
article explains how Lodash inspects input text, routes it to a
specialized Unicode word tokenizer, and preserves the integrity of
compound emojis.
The Challenge of Compound Emojis in JavaScript
JavaScript represents strings using UTF-16 code units. While standard characters fit into a single 16-bit code unit, modern emojis often exist outside the Basic Multilingual Plane (BMP) as surrogate pairs (two 16-bit units).
Compound emojis increase this complexity by combining multiple individual emojis into a single visual glyph. These include:
- Zero-Width Joiner (ZWJ) Sequences: Multiple
distinct emojis glued together by the
\u200Dcharacter (e.g., a technologist emoji composed of a person, a ZWJ, and a laptop). - Skin Tone Modifiers: Base emojis followed by one of
five Fitzpatrick scale modifiers
(
\uD83C[\uDFFB-\uDFFF]). - Regional Indicator Symbols: Two consecutive regional indicator characters that combine to render national flags.
- Keycap Sequences: A digit or symbol followed by an
emoji variation selector (
\uFE0F) and a combining enclosing keycap (\u20E3).
Standard JavaScript methods like
String.prototype.split('') or simplistic regular
expressions split these sequences at the surrogate or joiner boundary,
causing data corruption and rendering broken emoji fragments.
Step 1: Unicode Detection Routing
When _.words(string, pattern) is invoked without a
custom pattern argument, Lodash determines whether the input string
contains complex Unicode characters before running its tokenization
logic.
It checks the string against an internal regular expression—commonly
referenced as hasUnicodeWord in the Lodash source. This
check scans for code points outside the ASCII range, specifically
looking for astral symbols, variation selectors, diacritics, and the
zero-width joiner (\u200D).
- If the string contains only standard ASCII characters, Lodash routes
it to
asciiWords, a lightweight regular expression optimized for performance. - If complex Unicode is detected, Lodash routes the string to
unicodeWords, which deploys the heavy-duty Unicode parsing engine.
Step 2: The Structure of the Unicode Word Regex
The unicodeWords function relies on a compiled regular
expression composed of modular Unicode ranges. To handle compound emojis
alongside written scripts, Lodash constructs regex components that
explicitly match compound emoji mechanics:
- Surrogate Pair Matching: High and low surrogate ranges are explicitly grouped to treat 32-bit astral symbols as atomic units rather than two separate characters.
- Fitzpatrick Modifiers: The regex appends optional
modifiers (
[\uD83C[\uDFFB-\uDFFF]]) immediately following eligible person or hand glyphs to ensure tone adjustments remain attached to the base glyph. - Variation Selectors: Patterns include optional
matches for
\uFE0E(text presentation) and\uFE0F(emoji presentation), preventing selector bytes from detaching. - ZWJ Recursion Simulation: The regular expression
uses non-capturing groups structured around
\u200D. It defines an emoji pattern followed by(?:\u200D(?:pattern))*, allowing the regex engine to match indefinitely chained sequences (such as family or profession combinations) as a single token. - Flag Sequences: Pairs of Regional Indicator
characters (
[\uD83C\uDDE6-\uD83C\uDDFF]) are matched specifically in couples, ensuring flags are not split into isolated letters.
Step 3: Extraction and Output
Once the appropriate regular expression matches the text,
_.words uses String.prototype.match against
the compiled pattern. Because the emoji definitions within the pattern
have higher structural precedence and greedily consume modifiers and
ZWJ-linked sequences, the entire composite glyph is captured as an
unbroken string element.
The resulting array safely isolates standard language words alongside fully qualified compound emojis, maintaining the visual and technical integrity of the multi-byte characters.