Unicode String v2.4.0
This is the changelog for Unicode String v2.4.0 released on September 18th, 2026. For older changelogs please consult the release tag on GitHub
Module changes
Segmentation is now performed by table-driven engines generated from the state machine data published in PRI #555. The public API is unchanged — Unicode.String.split/2, next/2, stream/2, splitter/2, break?/2 and the casing functions behave exactly as before, and code using them needs no modification.
Four previously documented modules implemented the annexes by hand. They are now deprecated shims that delegate to the generated engines, so existing code keeps working and emits a compiler warning naming its replacement:
Behaviour is unchanged and the arities match — split/1, next/1 and break?/2 for grapheme, word and line, and split/3, next/3 and break?/4 for sentence — so migrating is a module rename. The one thing to know is that the former Unicode.String.Break.Line.split/1 applied the rules alone; that is Unicode.String.Dfa.Line.rule_split/1, while Unicode.String.Dfa.Line.split/1 also runs the dictionary pass for Thai, Lao, Khmer and Burmese.
Line and sentence gain locale-aware variants (Unicode.String.Dfa.Line.split/2, Unicode.String.Dfa.Sentence.split/3) carrying the CLDR tailoring described below.
These remain internal engines rather than a supported interface; Unicode.String is the API to prefer. The shims will be removed in a future major release.
Two modules are newly public: Unicode.String.Dfa, from which the four break engines are generated, and Unicode.String.Break.Tailoring, which holds CLDR's locale tailoring and abbreviation suppressions.
Enhancements
Support Unicode 18.0.0. Rule GB9c no longer requires a leading
Indic_Conjunct_Break=Consonant, so a linker opens a conjunct sequence from any position including the start of text. Segmentation test data is refreshed to 18.0.0.Segment all four break types with a table-driven engine generated from the state machine data published in PRI #555. Line breaking now passes all 19,346 cases of
LineBreakTest.txtwhere the previous engine passed 99.81%.Support CLDR locale tailoring of break classes through
Unicode.String.Break.Tailoring. Greek sentences break at U+003B and U+037E, andja,zhandzh-Hantline breaking treats conditional Japanese starters as ideographs rather than non-starters.Add an optional ICU4C backend,
Unicode.String.Nif, selected withbackend: :nifonUnicode.String.split/2. It is opt-in viaUNICODE_STRING_NIF=trueorconfig :unicode_string, :nif, true, requires ICU system libraries and:elixir_make, and falls back to the native implementation whenever it is unavailable, so the option is always safe to pass. Seeconformance.mdfor when it is worth enabling — end to end it is 5-7x faster for line breaking and the dictionary locales, but only 1.3-1.5x for word and grapheme breaking.
Performance
Skip the dictionary pass in line breaking for text that cannot contain a dictionary script. Thai, Lao, Khmer and Burmese all lie in U+0E01..U+17FF, which UTF-8 encodes with a lead byte of
0xE0or0xE1, and neither byte can occur as a continuation byte, so a single:binary.matchrules them out. Line breaking is 1.85x faster on Latin text.Skip the Unicode property table lookups for Latin-1 codepoints in all four break types. The break class of every codepoint below U+0100 is resolved at compile time into a tuple indexed by codepoint, and below U+00A9 no character is
Extended_Pictographicor carries anIndic_Conjunct_Breakvalue, so grapheme breaking skips those two tests entirely. Measured on 1,800 bytes of Latin text: word breaking 3.8x faster, sentence breaking 3.5x faster, line breaking 1.6x faster and grapheme breaking 1.4x faster.Decide grapheme and word boundaries from raw UTF-8 bytes where the answer is certain, without decoding a codepoint or consulting a property table. Two printable ASCII bytes in a row are always a grapheme boundary, and a run of ASCII letters is always a whole word provided the byte ending the run cannot join to it. Both preconditions are computed from the Unicode data at compile time. Grapheme breaking is 4.1x faster and word breaking a further 1.4x on Latin text.
Compile the
Extended_Pictographicproperty into a balanced binary tree of comparisons rather than a flat chain of 156orclauses. Becauseorshort-circuits on true, the flat form cost all 156 comparisons for every character that is not pictographic, which is almost every character in ordinary text. The tree answers in about 8 and remains valid in a guard.
Bug Fixes
Apply a locale's casing rules to the whole string. A character with no rule for the locale switched the remainder to the locale-independent rules, so any later locale-specific mapping was lost — Lithuanian
ifollowed by a combining dot above is the case that shows it.Implement the casing rules that remove a character.
SpecialCasing.txtleaves a mapping blank where the character is dropped in that context, which was read as an absent mapping: the combining dot above is now removed when lower casing after a Turkish or AzeriI, and when upper or title casing after a Lithuanian soft-dotted letter.Apply the Lithuanian dot-above rule to
Jas well asI.Jwas excluded from the generated mappings and handled by the ASCII fast path, so it never gained the dot that an accent above requires.Fix Turkish and Azeri lower casing of
Ibefore a combining dot above.Before_Dotis a condition on what follows the character, but was being tested against what precedes it, soIbecame dotlessıin a sequence where the standard keeps the dottedi.Fix locale-dependent casing duplicating the start of a string. Where a contextual rule did not apply, the fallback re-cased the character with an accumulator that already held everything mapped so far, emitting that prefix twice. Affected Turkish, Azeri and Lithuanian.
Keep dictionary-based line breaking inside its own script, so a boundary is added only between two characters of the dictionary script. Adjacent punctuation no longer becomes its own segment, which had broken after an opening bracket where LB14 forbids it and before a closing one where LB13 does.
Apply the line-break dictionary pass in
Unicode.String.stream/2andUnicode.String.splitter/2. Both previously returned different segments fromUnicode.String.split/2for Thai, Lao, Khmer and Burmese.Complete LB30b with its
[\p{Extended_Pictographic}&\p{Cn}] × EMalternative, so an unassigned pictographic keeps its emoji modifier. These characters carrylb=IDorlb=XX, so the rule cannot be expressed in line-break classes alone.Implement LB25 in full, tracking the
NU (SY | IS)*number run it is defined over. Numeric prefixes and postfixes now join only where a number is actually present, soPO × OPno longer suppresses a break unless a number follows the open punctuation.Implement LB28a, so breaks are suppressed inside the orthographic syllables of Brahmic scripts across the
AP,AK,AS,VIandVFclasses and U+25CC DOTTED CIRCLE.Implement LB19 and LB19a, so breaks are suppressed only before a non-initial and after a non-final quotation mark, and on both sides of any quotation mark that is not surrounded by East Asian characters. Previously every quotation mark suppressed breaks on both sides unconditionally.
Implement LB15a and LB15b, so a break is suppressed after an initial (
Pi) quotation mark across any following spaces, and before a final (Pf) quotation mark that ends the text or is followed by space, glue or closing punctuation. This also removes aQU SP* × OPrule that no longer exists in UAX #14.Apply the LB30 East-Asian-width restriction, so
(AL | HL | NU) × OPandCP × (AL | HL | NU)no longer suppress a break when the punctuation has anEast_Asian_WidthofF,WorH.Apply LB10 to a combining mark that begins a segment. A
CMorZWJwith no base to attach to is now treated asAL, where previously it kept classCMand admitted a spurious break before the following character.Resolve
Line_Break=SAby General_Category as LB1 requires, toCMforMnandMcand toALotherwise. Previously allSAresolved toAL, which broke sequences such as an ideograph followed by a Thai combining mark.
Unicode String v2.3.1
This is the changelog for Unicode String v2.3.1 released on August 16th, 2026. For older changelogs please consult the release tag on GitHub
Bug Fixes
Word breaking in a dictionary locale now applies the dictionary only to runs of text written in the script(s) that dictionary covers, with the standard Unicode rules governing everything else. Previously
Unicode.String.split("Japanese", break: :word, locale: :ja)returned each letter separately.Word and line breaking no longer raise a
File.Errorwhen the ICU dictionaries have not been downloaded withmix unicode.string.download.dictionaries. Segmentation now falls back to the standard Unicode rules, andUnicode.String.break/2andUnicode.String.splitter/2return{:error, reason}.
Unicode String v2.3.0
This is the changelog for Unicode String v2.3.0 released on July 23rd, 2026. For older changelogs please consult the release tag on GitHub
Enhancements
- Add
Unicode.String.word_like?/1which returns whether a segment contains alphabetic or numeric content, mirroring theisWordLikeproperty of JSIntl.Segmenterword segments (ICU's word-break rule status). Apply it to segments returned byUnicode.String.split/2withbreak: :word.
Unicode String v2.2.0
This is the changelog for Unicode String v2.2.0 released on July 9th, 2026. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Fix an unreachable
can_begin_word?/2clause that produced a compiler warning under--warnings-as-errors.
Enhancements
Add Credo (strict) to CI and development, a 90% test coverage gate, and a checked-in
mix formatpre-commit hook.Harden the CI workflow: OTP/Elixir-scoped dependency and build caches, refreshed toolchain matrix, and separate lint, coverage and Dialyzer stages.
Unicode String v2.1.0
This is the changelog for Unicode String v2.1.0 released on May 1st, 2026. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Improve line break segmentation conformance and compatibility with ICU.
Enhancements
- Replaces the regex-based segmentation engine with a single-pass DFA evaluator. Sentence break on a 4 KB unbroken sentence drops from ~9,200 ms to ~11 ms (~840×); word break on a 4 KB sentence from ~7,000 ms to ~12 ms (~580×); scaling is now linear in input length instead of O(N²).
Unicode String v2.0.1
This is the changelog for Unicode String v2.0.1 released on April 29th, 2026. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Fix compile + dialyzer + tests without optional :localize dependency.
Unicode String v2.0.0
This is the changelog for Unicode String v2.0.0 released on April 14th, 2026. For older changelogs please consult the release tag on GitHub
Breaking change
- Unicode String version 2.0 and later is supported on Elixir 1.17 or later only.
Enhancements
Replace
ex_cldrwithlocalizeas the localization libraryFix titalcasing the letter
i- including correct handling in Turkic languagesUse
Localize.Locale.best_match/3for locale matchingFixes to the
Unicode.Breakmodule.
Unicode String v1.8.0
This is the changelog for Unicode String v1.8.0 released on January 19th, 2026. For older changelogs please consult the release tag on GitHub
Enhancements
- Updates to Unicode 17.0 data.
Unicode String v1.7.0
This is the changelog for Unicode String v1.7.0 released on March 29th, 2025. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Converts all compile-time regex compilation to runtime to be compatible with OTP 28.
Unicode String v1.6.0
This is the changelog for Unicode String v1.6.0 released on March 17th, 2025. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Fix word break detection when a
\p{word_break=extend}codepoint is preceeded by a letter and followed by a letter.
Enhancements
- Updated to CLDR 47 break rules and test data.
Unicode String v1.5.0
This is the changelog for Unicode String v1.5.0 released on January 1st, 2025. For older changelogs please consult the release tag on GitHub
Enhancements
Update to CLDR 46.1 segmentation data and tests.
Pass dialyzer with
:underspecsflag set.
Unicode String v1.4.1
This is the changelog for Unicode String v1.4.1 released on March 14th, 2024. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Fix performance regressing in
Uncode.String.Break.next/4. Added the scriptbench/next.exsto allow for regression testing. Thanks to @mntns for the report. Closes #6.
Unicode String v1.4.0
This is the changelog for Unicode String v1.4.0 released on March 10th, 2024. For older changelogs please consult the release tag on GitHub
Enhancements
- Adds dictionary-based work breaking for Chinese (zh, zh-Hant, zh-Hans, zh-Hant-HK, yue, yue-Hans), Japanese (ja), Thai (th), Lao (lo), Khmer (km) and Burmese (my). These languages don't typically use whitespace to separate words so a dictionary lookup is more appropriate - although not perfect. The same dictionary is used for Chinese and Japanese. The dictionaries implemented are those used in the CLDR since they are under an open source license and also for consistency with ICU. Note that these dictionaries need to be downloaded with
mix unicode.string.download.dictionariesprior to use. Each dictionary will be parsed and loaded into persistent_term on demand. Each dictionary has a sizable memory footprint as measured by:persistent_term.info/0:
| Dictionary | Memory Mb |
|---|---|
| Chinese | 104.8 |
| Thai | 9.6 |
| Lao | 11.4 |
| Khmer | 38.8 |
| Burmese | 23.1 |
Unicode String v1.3.1
This is the changelog for Unicode String v1.3.1 released on March 6th, 2024. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Fix
Unicode.String.split/2andUnicode.String.next/2when the passing rule is:no_breakrule. Thanks to @GregLMcDonald for the report. Closes #5.
Unicode String v1.3.0
This is the changelog for Unicode String v1.3.0 released on February 27th, 2024. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Fix case folding for codepoints that fold to themselves.
Enhancements
Adds case mapping functions
Unicode.String.upcase/2,Unicode.String.downcase/2andUnicode/String.titlecase/2. These functions implement the full Unicode Casing algorithm including conditiional mappings. They are locale-aware and a locale can be specified as a string, atom or a Cldr.LanguageTag thereby providing basic integration betweenunicode_stringand ex_cldr.Case folding always follows the
:fullpath which allows mapping of single code points to multiple code points. There is no practical reason to implement the:simplepath. As a result, thetypeparameter toUnicode.String.Case.Folding.fold/2is no longer required or supported.Support an ex_cldr Language Tag as a parameter to
Unicode.String.Case.Folding.fold/2. In fact any map that has a:languagekey with a value that is an ISO 639-1 language code as a lower cased atom may be passed as a parameter.
Unicode String v1.2.1
This is the changelog for Unicode String v1.2.1 released on June 2nd, 2023. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Resolve segments dir at runtime, not compile time. Thanks to @crkent for the report. Closes #4.
Unicode String v1.2.0
This is the changelog for Unicode String v1.2.0 released on March 14th, 2023. For older changelogs please consult the release tag on GitHub
Enhancements
- Adds
Unicode.String.stream/2to support streaming graphemes, words, sentences and line breaks.
Unicode String v1.1.0
This is the changelog for Unicode String v1.1.0 released on September 21st, 2022. For older changelogs please consult the release tag on GitHub
Enhancements
- Updates the segmentation supplemental data (including locales) for CLDR. This adds the "sv" and "fi" locale data for sentence break suppressions.
Unicode String v1.0.1
This is the changelog for Unicode String v1.0.1 released on September 15th, 2021. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Woops, the priv/segments directory was not included in the build artifact
Unicode String v1.0.0
This is the changelog for Unicode String v1.0.0 released on September 14th, 2021. For older changelogs please consult the release tag on GitHub
Enhancements
- Update to use Unicode 14 release data.
Unicode String v0.3.0
This is the changelog for Unicode String v0.3.0 released on October 11th, 2020. For older changelogs please consult the release tag on GitHub
Bug Fixes
- Correct deps and docs to align with Elixir 1.11 and recent releases of
ex_unicode.
Unicode String v0.2.0
This is the changelog for Unicode String v0.2.0 released on July 12th, 2020. For older changelogs please consult the release tag on GitHub
Enhancements
This release implements the Unicode break rules for graphemes, words, lines (word-wrapping) and sentences.
Unicode String v0.1.0
This is the changelog for Unicode String v0.1.0 released on May 17th, 2020. For older changelogs please consult the release tag on GitHub
Enhancements
- Initial release