API reference
Convenience functions
.. py:function:: abbr2words(text, *, lang=’en’, context=True, initialism_mode=’dotted_only’, initialism_case=’source’, registered_initialism_mode=’expand’, annotations=None, protected_spans=None) :module: abbr2words
Expand known abbreviations in text.
The function expands abbreviations only. It intentionally does not normalize dates, times, numbers, currencies, or general punctuation. Optional annotations must use character offsets in the original source; POS guards fail open when usable lexical evidence is missing, and numeric units remain authoritative over generic POS predictions.
.. py:function:: abbr2words_with_replacements(text, *, lang=’en’, context=True, initialism_mode=’dotted_only’, initialism_case=’source’, registered_initialism_mode=’expand’, annotations=None, protected_spans=None) :module: abbr2words
Expand text and return exact source-aligned replacement metadata.
.. py:function:: iter_unit_matches(text, language, *, overrides=None, suppressed=None, protected_spans=()) :module: abbr2words
Yield structured source-aligned matches for numeric quantity symbols.
.. py:function:: iter_unit_diagnostics(text, language, *, overrides=None, suppressed=None, protected_spans=()) :module: abbr2words
Yield accepted unit matches and policy rejections for compact candidates.
.. py:function:: iter_initialism_diagnostics(text, language=’en’, *, context=True, initialism_mode=’dotted_only’, initialism_case=’source’, registered_initialism_mode=’expand’, protected_spans=None) :module: abbr2words
Yield source-aligned decisions for initialism-shaped candidates.
abbr2words(..., annotations=...) accepts an iterable of source-aligned
TokenAnnotation objects. Their offsets refer to the original input text;
labels are normalized and overlapping or invalid spans raise ValueError.
Missing lexical POS evidence fails open, and numeric unit guards remain
authoritative.
The context enum includes DEFAULT, TITLE, PLACE, TIME, DATE,
ACADEMIC, and RELIGIOUS. DATE is selected only by bounded numeric or
date-punctuation evidence in the local source window; it does not parse dates.
Language profiles may add stricter policies, and uncased scripts do not use the
cased-letter title heuristic.
English context profiles use positive place evidence for ambiguous dotted
spellings. Address/street evidence can expand a single compass letter, and
explicit Washington/place evidence can expand D.C.; personal and
bibliographic initials remain letter-spelled. Standalone uppercase dotted
initialisms of two through eight letters use a low-priority source-grapheme
fallback, so registered semantic rules such as e.g. and U.S. retain
precedence while E.G. can become E G.
Abbreviation boundaries use symmetric Unicode word-character lookarounds:
registered spellings may start or end with punctuation, but cannot attach to a
surrounding \w character. Optional protected_spans=[(start, end), ...]
prevents replacements in caller-owned ranges such as URLs, markup, or code.
For source-aligned diagnostics or downstream text alignment, use
abbr2words_with_replacements(...) or
Expander.expand_with_replacements(...). The immutable ExpansionResult
contains the original source_text, expanded text, and deterministic,
non-overlapping ExpansionReplacement records. Replacement offsets refer to
the original input, and applying the records from right to left reproduces the
result exactly. expand_with_trace(...) remains as a compatibility view of the
same result. Existing convenience calls continue to return strings.
from abbr2words import abbr2words_with_replacements
result = abbr2words_with_replacements("Prof. Klein, S. 12", lang="de")
print(result.text)
for replacement in result.replacements:
print(replacement.start, replacement.end, replacement.text, replacement.kind)
Initialism policies
The public expansion functions and get_expander(), get_shared_expander(),
and Expander accept these optional policy arguments:
abbr2words(
"NGO BBC PDF",
initialism_mode="conservative_undotted", # default: "dotted_only"
initialism_case="lower", # "source", "upper", or "lower"
registered_initialism_mode="expand", # or explicit "spell"
)
The default preserves existing behavior for unknown uppercase text. The
reviewed registry intentionally owns a small set of common initialisms such as
BBC, US, UK, ISBN, HTML, and TV, which render source graphemes as
ordinary abbreviation entries. conservative_undotted recognizes only
high-confidence standalone ASCII uppercase residuals from two through eight
letters and rejects reviewed lexical acronyms, ambiguous words, headline runs,
Roman numerals, and structured identifiers. spell_undotted retains the broad
historical opt-in behavior and renders standalone source-aligned graphemes.
Neither mode parses numbers, URLs, e-mail addresses, versions, product codes,
phone numbers, stock tickers, or Roman numerals. Callers should reserve typed
structured spans first, then use the conservative policy for remaining
uppercase tokens. registered_initialism_mode="spell" affects only
reviewed registry entries carrying the explicit speech_strategy="spell_source"
metadata; semantic registry expansions remain the default.
The compatibility surface is intentionally conservative:
Source |
Detection mode |
Case |
Registered mode |
Result |
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dotted |
|
|
|
|
dotted |
|
|
|
The final period in the U.S. row is source sentence punctuation retained by
the existing replacement policy. Reviewed entries continue to outrank the
generic fallback, while Roman-only tokens and structured identifier
components remain excluded.
The shared-expander cache includes all policy values, so expanders with
different initialism behavior are independent instances. Fallback replacement
records use abbr:initialism for dotted matches and
abbr:initialism-conservative or abbr:initialism-undotted for undotted
matches. iter_initialism_diagnostics() reports source-aligned start/end,
source_text, language, candidate_kind, decision, stable reason, and
registered_entry_id fields. Protected spans are reported as
reason="protected" and are never claimed.
The bundled language registry follows a 66-key current-master parity snapshot:
49 base keys plus the explicit locale overlays en_GB, en_IN, en_NG,
en_US, es_CO, es_CR, es_GT, es_MX, es_NI, es_VE, fr_BE,
fr_CH, fr_DZ, pt_BR, zh_CN, zh_HK, and zh_TW. normalize_language() returns an exact locale
key when registered and otherwise its base key. Turkish unit symbols followed by straight or
curly apostrophe suffixes are intentionally not expanded until suffix
realization is implemented.
Bundled identity lexical rules are rejected. Locale currencies and similar
structured identities are recognized only in numeric quantity context, while
iter_unit_matches() remains the semantic API for canonical IDs and exact
source offsets. Non-English baseline unit replacement text is a localized
neutral label, not a complete quantity grammar.
.. py:function:: expand(text, *, lang=’en’, context=True, initialism_mode=’dotted_only’, initialism_case=’source’, registered_initialism_mode=’expand’, annotations=None, protected_spans=None) :module: abbr2words
Expand known abbreviations in text.
The function expands abbreviations only. It intentionally does not normalize dates, times, numbers, currencies, or general punctuation. Optional annotations must use character offsets in the original source; POS guards fail open when usable lexical evidence is missing, and numeric units remain authoritative over generic POS predictions.
.. py:function:: normalize_language(lang) :module: abbr2words
Normalize and resolve an ISO-style language or locale code.
.. py:function:: base_language(lang) :module: abbr2words
Return the resolved base language for a language or locale input.
.. py:function:: supported_languages(*, include_locales=True) :module: abbr2words
Return sorted bundled language and, optionally, locale keys.
.. py:function:: get_expander(lang=’en’, *, context=True, initialism_mode=’dotted_only’, initialism_case=’source’, registered_initialism_mode=’expand’) :module: abbr2words
Return a new, independently mutable language expander.
.. py:function:: get_shared_expander(lang=’en’, *, context=True, initialism_mode=’dotted_only’, initialism_case=’source’, registered_initialism_mode=’expand’) :module: abbr2words
Return the shared registry for a language, context, and policy.
.. py:function:: reset_expanders(lang=None) :module: abbr2words
Reset one or all shared language registries.
Mutable facade
.. py:class:: Expander(lang=’en’, *, context=True, initialism_mode=’dotted_only’, initialism_case=’source’, registered_initialism_mode=’expand’) :module: abbr2words :canonical: abbr2words.api.Expander
Small facade for a mutable, language-specific abbreviation registry.
.. py:method:: Expander.call(text, *, annotations=None, protected_spans=None) :module: abbr2words
Expand abbreviations using this instance's registry.
``annotations`` are source-aligned to the original text. Only coarse
``pos`` labels participate in guards; fine-grained ``tag`` values are
retained as metadata.
.. py:method:: Expander.abbreviations() :module: abbr2words
Return the configured abbreviation spellings.
.. py:method:: Expander.add(abbreviation, expansion, *, context_expansions=None, case_sensitive=False, description=’’, only_if_preceded_by=None, only_if_followed_by=None, only_if_pos=None, not_if_pos=None, case_policy=’fixed’, speech_strategy=’expand’, aliases=()) :module: abbr2words
Add or replace an abbreviation, optionally constrained by POS.
A string is one POS label; collections support multiple labels. Deny
constraints take precedence over allow constraints.
.. py:method:: Expander.add_custom_abbreviation(abbreviation, expansion, description=’’, case_sensitive=False, only_if_preceded_by=None, only_if_followed_by=None, only_if_pos=None, not_if_pos=None, case_policy=’fixed’) :module: abbr2words
Register an entry using string-named context expansions.
.. py:method:: Expander.expand(text, *, annotations=None, protected_spans=None) :module: abbr2words
Expand abbreviations using this instance's registry.
``annotations`` are source-aligned to the original text. Only coarse
``pos`` labels participate in guards; fine-grained ``tag`` values are
retained as metadata.
.. py:method:: Expander.expand_with_replacements(text, *, annotations=None, protected_spans=None) :module: abbr2words
Expand abbreviations and return exact replacement metadata.
.. py:method:: Expander.expand_with_trace(text, *, annotations=None, protected_spans=None) :module: abbr2words
Compatibility alias for :meth:`expand_with_replacements`.
.. py:method:: Expander.has(abbreviation, *, case_sensitive=False) :module: abbr2words
Return whether this instance contains an abbreviation.
.. py:method:: Expander.iter_initialism_diagnostics(text, *, protected_spans=None) :module: abbr2words
Yield source-aligned initialism decisions for this expander.
.. py:method:: Expander.iter_unit_matches(text, *, protected_spans=()) :module: abbr2words
Yield structured matches using this expander's unit customization.
.. py:method:: Expander.remove(abbreviation, *, case_sensitive=False) :module: abbr2words
Remove an abbreviation from this instance.
.. py:method:: Expander.remove_unit(symbol) :module: abbr2words
Suppress a reviewed unit for this isolated expander.
.. py:method:: Expander.set_unit(symbol, expansion, *, case_sensitive=True, description=’Custom unit’, canonical_id=None, category=’unit’) :module: abbr2words
Override a reviewed unit for this isolated expander.
Guarded unit symbols
The stable API expands a reviewed set of unit symbols only when a numeric value
precedes the complete unit expression. Numeric forms such as 500 g, 500g,
1.5 kg, 1,5 kg, and 5 km/h are supported; standalone symbols and attached
words remain unchanged. This is symbol expansion, not number spelling, unit
conversion, or universal UCUM parsing.
The matcher is maximal and fail-closed: larger unsupported expressions such as
5 km / h, 1 m^2, and 2kg-rated remain unchanged instead of being
partially rewritten. Reviewed aliases include both µg and μg; unrelated
source characters are not Unicode-normalized. Unit metadata controls case
sensitivity, whether a numeric value is required, and whether a separator is
required between a numeric value and an ambiguous one-letter symbol. The
separator requirement defaults to false for compatibility; reviewed B, A,
and K candidates require spacing so compact identifier-like forms are not
claimed as units.
Unit replacements have kind="unit" in the exact replacement result. This
layer expands unit symbols/abbreviations lexically; it does not verbalize the
numeric quantity or choose grammatical singular/plural forms. Callers that
need a phrase such as zwei Minuten should consume the complete numeric
quantity in a structured quantity stage before calling abbreviation expansion.
abbr2words("500 g", lang="en") # "500 gram"
abbr2words("section g", lang="en") # "section g"
Structured quantity matches
Use iter_unit_matches() when a downstream semantic stage needs the recognized
quantity before it performs number or grammar realization:
from abbr2words import iter_unit_matches
source = "Für 1,5 kg Mehl"
match = next(iter_unit_matches(source, "de"))
assert source[match.start : match.end] == "1,5 kg"
assert source[match.value_start : match.value_end] == "1,5"
assert match.value == "1,5"
assert match.symbol == "kg"
assert match.canonical_id == "mass-kilogram"
UnitMatch is immutable and source-aligned. Its start:end range covers the
complete numeric expression and symbol; value_start:value_end identifies the
original numeric lexeme exactly. Matches are deterministic, maximal, and
non-overlapping. protected_spans=[(start, end), ...] suppresses caller-owned
ranges such as markup, URLs, or code. overrides and suppressed accept unit
symbols; suppression also accepts a canonical ID.
iter_unit_diagnostics() returns the same accepted decisions plus compact
separator-policy rejections with status="rejected" and
reason="requires_separator". Each record retains the symbol, locale, and
canonical identity so downstream ownership diagnostics do not need to infer
decisions from replacement text.
The matcher recognizes and identifies quantity symbols. It does not decide how
the complete quantity is spoken: number-to-words conversion, singular/plural
grammar, currency decomposition, and locale-specific decimal policy belong to
the consuming semantic normalizer. Currency and magnitude matches expose their
category without turning this package into a structured-number parser.
Reviewed semantic identities include speed, pressure, data, fuel-consumption,
and flow units plus JPY, CHF, INR, KRW, and MXN currencies. The es_MX
overlay gives unqualified $ the Mexican-peso identity while US$ and USD
remain US dollar. These are recognition contracts for a downstream consumer,
not amount or number grammar.
Core types
.. py:class:: TokenAnnotation(start, end, pos=None, tag=None) :module: abbr2words :canonical: abbr2words.annotations.TokenAnnotation
A provider-neutral token annotation aligned to the source text.
Offsets use Python string indices: text[start:end]. pos is
normally an uppercase coarse Universal POS label; tag may contain a
provider-specific fine-grained tag.
.. py:class:: AbbreviationEntry(abbreviation, expansion, context_expansions=None, variants=(), case_sensitive=False, description=’’, only_if_preceded_by=None, only_if_followed_by=None, only_if_pos=None, not_if_pos=None, boundary=’word’, left_boundary=None, right_boundary=None, origin=’bundled’, aliases=(), case_policy=’fixed’, speech_strategy=’expand’) :module: abbr2words :canonical: abbr2words.core.AbbreviationEntry
A single abbreviation with its expansion(s).
.. attribute:: abbreviation
The abbreviated form (e.g., "Prof.")
:type: str
.. attribute:: expansion
Default expansion (e.g., "Professor")
:type: str
.. attribute:: context_expansions
Optional dict of context-specific expansions
:type: dict[abbr2words.core.AbbreviationContext, str] | None
.. attribute:: case_sensitive
Whether matching should be case-sensitive
:type: bool
.. attribute:: description
Human-readable description of the abbreviation
:type: str
.. attribute:: only_if_preceded_by
Optional regex that must match the text immediately
before the abbreviation match (typically anchored with $).
:type: str | re.Pattern[str] | None
.. attribute:: only_if_followed_by
Optional regex that must match the suffix immediately
after the abbreviation match. The pattern is matched against
``text[end:]``; therefore ``^`` means immediately after this
candidate, not the beginning of the complete source string.
:type: str | re.Pattern[str] | None
.. attribute:: only_if_pos
Optional coarse POS label or labels. POS evidence is
evaluated only when usable source-aligned annotations are present.
:type: str | collections.abc.Collection[str] | None
.. attribute:: not_if_pos
Optional coarse POS label or labels that veto a match when
they overlap the abbreviation. This guard takes precedence over
``only_if_pos``.
:type: str | collections.abc.Collection[str] | None
.. py:method:: AbbreviationEntry.get_expansion(context=None) :module: abbr2words
Get the appropriate expansion for the given context.
:param context: The context type, or None for default
:returns: The expanded form
AbbreviationEntry.variants is an ordered tuple of immutable,
declarative ExpansionVariant values. The first variant whose guards match
the original source wins, followed by existing context and default expansion
fallback. Variants do not accept callbacks.
AbbreviationEntry.case_policy is "fixed" by default. Set it to
"sentence" only for reviewed lexical expansions whose canonical stored form
is appropriate in mid-sentence text. The matcher applies it after selecting a
variant or context expansion, and aliases share the entry policy. Dotted
abbreviations retain one final period when their consumed dot is also
sentence-final.
.. py:class:: ExpansionVariant(expansion, only_if_preceded_by=None, only_if_followed_by=None, only_if_pos=None, not_if_pos=None) :module: abbr2words :canonical: abbr2words.core.ExpansionVariant
One ordered, declarative conditional expansion for an abbreviation.
Variants deliberately reuse the entry guard vocabulary instead of accepting callbacks. This keeps registry data serializable and makes selection deterministic and safe to evaluate against the original source text.
AbbreviationEntry.only_if_pos and not_if_pos accept coarse POS labels such
as NOUN, PROPN, and ADP. They are evaluated only when annotations are
provided. Expander.add() exposes the same optional only_if_pos and
not_if_pos keyword arguments, plus aliases=(...) for additional source
spellings that share the entry’s guards, case policy, and speech strategy.
The abbreviation stage returns lexical replacements with source-aligned spans;
it does not interpret following numbers, dates, decimals, structured
identifiers, article elision, surrounding grammar, or speech rendering. Those
concerns remain with the consuming normalizer, including spokenform.
.. py:class:: AbbreviationContext(*values) :module: abbr2words :canonical: abbr2words.core.AbbreviationContext
Context types for disambiguating abbreviations.
.. py:class:: ExpansionMatch(start, end, source_text, replacement, language, entry_id, kind, context, priority) :module: abbr2words :canonical: abbr2words.core.ExpansionMatch
One accepted source-aligned expansion from :meth:expand_with_trace.
.. py:class:: AbbreviationExpander(enable_context_detection=True, *, initialism_mode=’dotted_only’, initialism_case=’source’, registered_initialism_mode=’expand’) :module: abbr2words :canonical: abbr2words.core.AbbreviationExpander
Abstract base class for language-specific abbreviation expanders.
.. py:method:: AbbreviationExpander.add_abbreviation(entry) :module: abbr2words
Add an abbreviation entry.
:param entry: The abbreviation entry to add
.. py:method:: AbbreviationExpander.add_custom_abbreviation(abbreviation, expansion, description=’’, case_sensitive=False, only_if_preceded_by=None, only_if_followed_by=None, only_if_pos=None, not_if_pos=None, case_policy=’fixed’, aliases=()) :module: abbr2words
Add or replace an entry using string context names and POS guards.
A single POS string is treated as one label, while a collection can
express several accepted or denied labels. Labels are normalized by
:class:`AbbreviationEntry`.
.. py:method:: AbbreviationExpander.expand(text, *, annotations=None, protected_spans=None) :module: abbr2words
Expand all abbreviations in the text.
:param text: Input text containing abbreviations
:param annotations: Optional provider-neutral annotations aligned to the
original source offsets. Incomplete lexical POS evidence does
not suppress a structurally valid match.
:returns: Text with abbreviations expanded
.. py:method:: AbbreviationExpander.expand_with_replacements(text, *, annotations=None, protected_spans=None) :module: abbr2words
Expand text and return exact immutable replacement metadata.
.. py:method:: AbbreviationExpander.expand_with_trace(text, *, annotations=None, protected_spans=None) :module: abbr2words
Compatibility alias for :meth:`expand_with_replacements`.
.. py:method:: AbbreviationExpander.get_abbreviation(abbreviation, case_sensitive=False) :module: abbr2words
Get an abbreviation entry.
:param abbreviation: The abbreviation to retrieve (e.g., "Dr.")
:param case_sensitive: Whether to match case-sensitively
:returns: The abbreviation entry if found, None otherwise
.. py:method:: AbbreviationExpander.get_abbreviations_list() :module: abbr2words
Get a list of all supported abbreviations.
:returns: List of abbreviation strings
.. py:method:: AbbreviationExpander.has_abbreviation(abbreviation, case_sensitive=False) :module: abbr2words
Check if an abbreviation exists.
:param abbreviation: The abbreviation to check (e.g., "Dr.")
:param case_sensitive: Whether to match case-sensitively
:returns: True if the abbreviation exists, False otherwise
.. py:method:: AbbreviationExpander.iter_initialism_diagnostics(text, *, protected_spans=()) :module: abbr2words
Yield initialism decisions using this expander's registry and policy.
.. py:method:: AbbreviationExpander.iter_unit_matches(text, *, protected_spans=()) :module: abbr2words
Yield structured matches using this expander's unit customization.
.. py:method:: AbbreviationExpander.remove_abbreviation(abbreviation, case_sensitive=False) :module: abbr2words
Remove an abbreviation entry.
:param abbreviation: The abbreviation to remove (e.g., "Dr.")
:param case_sensitive: Whether to match case-sensitively
:returns: True if the abbreviation was found and removed, False otherwise
.. py:method:: AbbreviationExpander.remove_unit(symbol) :module: abbr2words
Suppress a bundled unit or remove an instance-local unit override.
.. py:method:: AbbreviationExpander.set_unit(symbol, expansion, *, case_sensitive=True, description=’Custom unit’, canonical_id=None, category=’unit’) :module: abbr2words
Override one reviewed unit for this expander instance.
.. py:class:: ExpansionReplacement(start, end, text, source, kind, language, abbreviation=None, rule=None, priority=0, context=None) :module: abbr2words :canonical: abbr2words.core.ExpansionReplacement
One accepted replacement against the original source text.
.. py:property:: ExpansionReplacement.entry_id :module: abbr2words :type: str
Compatibility alias for the stable rule/source identifier.
.. py:property:: ExpansionReplacement.replacement :module: abbr2words :type: str
Compatibility alias for the replacement text.
.. py:class:: ExpansionResult(source_text, text, replacements) :module: abbr2words :canonical: abbr2words.core.ExpansionResult
Expanded text together with accepted source replacements.
.. py:property:: ExpansionResult.matches :module: abbr2words :type: tuple[~abbr2words.core.ExpansionMatch, …]
Return the legacy trace view of :attr:`replacements`.
.. py:class:: UnitMatch(start, end, value_start, value_end, value, symbol, canonical_id, canonical_symbol, expansion, language, category=’unit’, ambiguity=’none’, separator=’’) :module: abbr2words :canonical: abbr2words.units.UnitMatch
One immutable, source-aligned recognized numeric quantity symbol.
.. py:class:: ProtectedSpan(start, end, kind=None) :module: abbr2words :canonical: abbr2words.core.ProtectedSpan
A source range that must not be changed by expansion.
.. py:class:: UnitEntry(symbols, expansion, case_sensitive=True, description=’’, canonical_symbol=None, requires_numeric_value=True, canonical_id=None, reject_following_apostrophe=False, category=’unit’, quantity_position=’suffix’, allow_lexical_overlap=False, preserve_sentence_final_period=False, reject_following_period=False, requires_separator=False) :module: abbr2words :canonical: abbr2words.units.UnitEntry
A localized unit spelling recognized only after a numeric quantity.
The public abbr2words.core.abbreviation_guards_match() helper accepts either
an AnnotationIndex or an annotation iterable. Iterable input is normalized
and validated the same way as expansion. It evaluates coarse pos only;
provider-specific tag values are retained but not matched.