Skip to main content

extended-wer-normalizer

jiwer-compatible text normalizer for Word Error Rate (WER) evaluation in voice AI.

Extends jiwer's built-in transforms with normalizations that matter for real-world ASR evaluation: phone numbers, emails, URLs, currency, percentages, ordinals, filler words, and stuttering.

Installation

pip install extended-wer-normalizer

Quick start

from extended_wer_normalizer import normalize_for_wer

normalize_for_wer("Call 0176 or email info@example.com, it costs $5.99")
# → "call 0 1 7 6 or email info at example dot com it costs five dollars ninety nine cents"

normalize_for_wer("Um, 1st place goes to Dr. Smith with 50% accuracy")
# → "first place goes to doctor smith with fifty percent accuracy"

jiwer integration

Every normalization is a jiwer.AbstractTransform subclass — compose them freely:

import jiwer
from extended_wer_normalizer.transforms import NormalizeEmails, ExpandDigitRuns

pipeline = jiwer.Compose([
    NormalizeEmails(),
    ExpandDigitRuns(),
    jiwer.ToLowerCase(),
    jiwer.RemovePunctuation(),
    jiwer.ReduceToListOfListOfWords(),
])

wer = jiwer.wer("info at example dot com", "info@example.com", hypothesis_transform=pipeline)

Use the pre-built pipeline directly with jiwer.wer:

import jiwer
from extended_wer_normalizer import english_wer_pipeline

wer = jiwer.wer(reference, hypothesis, reference_transform=english_wer_pipeline, hypothesis_transform=english_wer_pipeline)

Available transforms

Transform Example
ExpandDigitRuns "0176" → "0 1 7 6"
DigitWordsToChars "zero one seven" → "0 1 7"
NormalizeEmails "user@example.com" → "user at example dot com"
NormalizeURLs "https://example.com/path" → "example dot com"
NormalizeCurrency "$5.99" → "five dollars ninety nine cents"
NormalizePercentages "50%" → "fifty percent"
NormalizeOrdinals "1st" → "first", "15th" → "fifteenth"
ExpandAbbreviations "Dr." → "doctor", "vs." → "versus"
NormalizeSymbols "cats & dogs" → "cats and dogs"
SplitHyphenatedWords "fixed-term" → "fixed term"
RemoveFillerWords removes um, uh, hmm, er, ah, …
CollapseRepetitions "yes yes yes yes" → "yes" (collapses runs of 4+; configurable via max_repeats)
ExpandFrenchElisions "j'aime" → "j aime", "qu'il" → "qu il" (French only)

Every transform that consumes language-specific data accepts a language="en" keyword (default English): NormalizeEmails(language="fr"), ExpandAbbreviations(language="de"), etc.

Pipeline design

The English pipeline applies transforms left-to-right in a single pass:

  1. Pattern-specific (before punctuation is stripped): email, URL, symbol, abbreviation, currency, percentage, ordinal
  2. Core: contractions (I'm → i am), lowercase, intra-word hyphen split (fixed-term → fixed term), punctuation removal
  3. Digit normalization: expand digit runs (0176 → 0 1 7 6), convert digit words (zero → 0)
  4. Cleanup: filler words, repetition collapse

Supported languages

Full pipelines (with language-specific abbreviations, fillers, lexicons, and number/ordinal/percentage word forms via num2words) ship for English, German, and French. Pass any other language value for the minimal fallback (lowercase + punctuation + whitespace).

from extended_wer_normalizer import normalize_for_wer

# German: titles, fillers, ordinals, currency
normalize_for_wer("Hr. Müller, am 1. Januar, ähm, ungefähr 50% Rabatt", language="de")
# → "herr müller am erste januar ungefähr fünfzig prozent rabatt"

# French: elision contractions, ordinals, comma-decimal currency
normalize_for_wer("M. Dupont, le 1er janvier, c'est €5,99", language="fr")
# → "monsieur dupont le premier janvier c est cinq euros quatre vingt dix neuf centimes"

# Spanish, Italian, … fall through to the minimal pipeline
normalize_for_wer("¡Hola, mundo!", language="es")
# → "hola mundo"

# Tune the repetition-collapse threshold (default 3 → collapse runs of 4+)
normalize_for_wer("no no no", max_repeats=1)  # collapse any 2+ run
# → "no"

Per-language pipelines are also exposed for direct use with jiwer.wer:

from extended_wer_normalizer import (
    english_wer_pipeline,
    german_wer_pipeline,
    french_wer_pipeline,
)

To inspect or extend the language data:

from extended_wer_normalizer.languages import get_language_data, supported_languages

supported_languages()              # ["de", "en", "fr"]
get_language_data("de").abbreviations["hr."]  # "herr"

Quirks worth knowing

  • Hyphenated compounds: intra-word hyphens split into spaces (fixed-term → fixed term), so hyphenated and spaced spellings of the same words score identically. Before 0.6.0 the hyphen was deleted (fixedterm), which penalized STTs that never emit hyphens — WER numbers are not comparable across that boundary.
  • Comma vs. period decimals: French uses , (€5,99, 3,5%); the currency and percentage transforms accept either separator regardless of language.
  • German ordinals: matched as 1- to 3-digit numbers followed by . and a word (e.g. "1. Januar" but not "Es war 1990." or "1.5 Liter"). 4+ digits and decimals are skipped to avoid false positives on years.
  • French ordinals: matched as 1er, 1ère, 2e, 2es, 2ème, 2èmes, 2nde, 2nds, 2nd. num2words returns masculine forms (premier, deuxième); feminine variants like première or seconde are not produced.
  • Contractions: jiwer.ExpandCommonEnglishContractions runs only for English. French has a custom ExpandFrenchElisions that splits j', l', d', n', s', m', t', c', qu', jusqu', lorsqu', puisqu', quoiqu' from the following word. German has no contraction step.
  • German pluralization: most currency units stay invariant (fünf Euro, not fünf Euros).

Metadata

Release files for extended-wer-normalizer 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for extended-wer-normalizer 0.6.0
File Size Uploaded
extended_wer_normalizer-0.6.0.tar.gz 51.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for extended-wer-normalizer 0.6.0
File Interpreter ABI Platform
extended_wer_normalizer-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 68.5 kB

Release files / extended_wer_normalizer-0.6.0.tar.gz

Download URL extended_wer_normalizer-0.6.0.tar.gz
Size 51.3 kB
Tags Source
SHA-256 checksum
How to use checksums
1ef763523dafc5ab6fad42f1d4769fba0f0233aeeeda7c1cbed85aeb1ab4d4f2
BLAKE2b-256 checksum
How to use checksums
9487a94b4fb036a15792942053e06312de84301afdc41730d2b7f1ba5f034c5a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / extended_wer_normalizer-0.6.0-py3-none-any.whl

Download URL extended_wer_normalizer-0.6.0-py3-none-any.whl
Size 17.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
743d0f3b533617196d23d63c547c2488db32c5f5bbe854e0691b0b87e19e33d9
BLAKE2b-256 checksum
How to use checksums
8f5e0733554e1a1885d208b6141321cd8c633cd6fe8341f29ab5931e1564229e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page