This is the changelog for Unicode String v2.4.1 released on September 20th, 2026. For older changelogs please consult the release tag on GitHub
Unicode.String.Break.Grapheme,…Word,…Sentenceand…Lineare deprecated and will be removed in 2.5.0. They have delegated toUnicode.String.Dfa.*since 2.4.0 and each function now names 2.5.0 in the warning it emits; the arities match, so migrating is a module rename.
-
Resolve uncontextual case mappings from a lookup table rather than one generated function clause each, which takes
casing/6from 4,776 clauses to 37 and a clean compile from 47 seconds to 4.4. Non-ASCII case conversion is roughly 1.4x slower in exchange; ASCII and the locale-specific rules are unchanged. -
Compile the regular expressions that locale-specific casing tests its context with, rather than interpolating them into a sigil at the point of use. An interpolated sigil is not a literal so it recompiled a pattern of roughly 9KB on every character it examined: Greek lower casing is 49x faster, Turkish 46x, and Greek upper casing 11x.
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
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:
| Deprecated | Replacement |
|---|---|
Unicode.String.Break.Grapheme |
Unicode.String.Dfa.Grapheme |
Unicode.String.Break.Word |
Unicode.String.Dfa.Word |
Unicode.String.Break.Sentence |
Unicode.String.Dfa.Sentence |
Unicode.String.Break.Line |
Unicode.String.Dfa.Line |
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 2.5.0.
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.
-
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. See the Conformance guide for 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.
-
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.
-
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.
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
-
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}.
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
- 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.
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
- Fix an unreachable
can_begin_word?/2clause that produced a compiler warning under--warnings-as-errors.
-
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.
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
- Improve line break segmentation conformance and compatibility with ICU.
- 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²).
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
- Fix compile + dialyzer + tests without optional :localize dependency.
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
- Unicode String version 2.0 and later is supported on Elixir 1.17 or later only.
-
Replace
ex_cldrwithlocalizeas the localization library -
Fix titalcasing the letter
i- including correct handling in Turkic languages -
Use
Localize.Locale.best_match/3for locale matching -
Fixes to the
Unicode.Breakmodule.
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
- Updates to Unicode 17.0 data.
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
- Converts all compile-time regex compilation to runtime to be compatible with OTP 28.
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
- Fix word break detection when a
\p{word_break=extend}codepoint is preceeded by a letter and followed by a letter.
- Updated to CLDR 47 break rules and test data.
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
-
Update to CLDR 46.1 segmentation data and tests.
-
Pass dialyzer with
:underspecsflag set.
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
- 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.
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
- 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 |
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
- Fix
Unicode.String.split/2andUnicode.String.next/2when the passing rule is:no_breakrule. Thanks to @GregLMcDonald for the report. Closes #5.
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
- Fix case folding for codepoints that fold to themselves.
-
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.
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
- Resolve segments dir at runtime, not compile time. Thanks to @crkent for the report. Closes #4.
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
- Adds
Unicode.String.stream/2to support streaming graphemes, words, sentences and line breaks.
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
- Updates the segmentation supplemental data (including locales) for CLDR. This adds the "sv" and "fi" locale data for sentence break suppressions.
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
- Woops, the priv/segments directory was not included in the build artifact
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
- Update to use Unicode 14 release data.
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
- Correct deps and docs to align with Elixir 1.11 and recent releases of
ex_unicode.
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
This release implements the Unicode break rules for graphemes, words, lines (word-wrapping) and sentences.
-
Adds
Unicode.String.split/2 -
Adds
Unicode.String.break?/2 -
Adds
Unicode.String.break/2 -
Adds
Unicode.String.splitter/2 -
Adds
Unicode.String.next/2
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
- Initial release