Skip to main content

urdunorm

PyPI Python CI DOI License

Urdu text normalization and WER/CER scoring for ASR evaluation, under named protocols you can report. Zero runtime dependencies. pip install urdunorm

The problem, in five lines

from urdunorm import wer

reference = ["کے لیے شکریہ"]  # what the transcriber wrote
hypothesis = ["کیلئے شکریہ"]  # what the model emitted, compound joined

wer(reference, hypothesis)  # 0.0
wer(reference, hypothesis, mode="lums-compat")  # 0.667

Same audio, same words, one spelling difference, two published protocols. That gap is why Urdu ASR results do not compare across papers, and why this package makes you name the protocol.

What it does to text, under eval

input output what happened
علي كي علی کی Arabic-keyboard letters unified to their Urdu equivalents. Same word, different keyboard.
ﻤﯿﮟ میں Presentation forms, common in PDF-extracted text, folded to normal letters.
مُحَمَّد محمد Vowel diacritics stripped. Optional in writing, so a model is not charged for omitting them.
۲۰۲۶ 2026 All three numeral systems Urdu uses folded onto one.
کیلئے کے لیے A compound written without its space, repaired. WER counts whitespace tokens, so this alone costs two errors.
بھائی بھائی Unchanged. That letter marks aspiration and is phonemic. Merging it into its lookalike reports a lower WER by destroying the distinction.

The last row matters most: phonemic characters are a contract, and the package refuses to import if a rule table would merge one.

How it differs from urduhack and LughaatNLP

Those are general Urdu NLP toolkits: tokenizers, POS tagging, NER. This is an evaluation protocol, normalization plus scoring, nothing else. Different jobs.

Differences are measured, not asserted. This table is generated by compare_normalizers.py --emit-table running each package at a pinned version:

what it is input urdunorm urduhack LughaatNLP
Arabic-keyboard yeh and kaf علي كي دكان علی کی دکان علی کی دکان علي كي دكان
presentation forms ﻤﻴﮟ میں مےں ﻤﻴﮟ
vowel diacritics مُحَمَّد محمد محمّد محمد
Urdu-Indic digits ۲۰۲۶ 2026 ۲۰۲۶ ۲۰۲۶
joined compound کیلئے کے لیے کیلئے کیلئے
aspiration, must not change بھائی بھائی بھائی بھائی
alef madda, must not change آج آج آج اج

Measured on urdunorm 0.1.0, urduhack 1.1.1, LughaatNLP 1.3.1.

Both also carry heavy dependencies: urduhack imports TensorFlow at package import; LughaatNLP requires torch, transformers, scikit-learn and scipy.

Modes

Mode Characters Diacritics Punctuation Digits Space repair ZWNJ
eval unified stripped dropped unified on to space
display unified kept kept kept off kept
lums-compat unified stripped 5 chars only unified off to space

Use eval unless you know why not. display is for showing transcripts to people. lums-compat reproduces WER We Stand (COLING 2025), the only published Urdu ASR benchmark, so numbers can be compared against it. Its five-character punctuation class keeps the Urdu full stop: that is theirs, not a bug here. Report under two protocols; a single-protocol Urdu WER compares to nothing.

Scoring

from urdunorm import wer, cer, score, normalize, EVAL

normalize("کیلئے", mode="eval")
wer(references, hypotheses, mode="eval")
cer(references, hypotheses, mode="eval")

result = score(references, hypotheses, mode="eval")
str(result)  # 'WER 12.40% [eval]'
EVAL.with_(repair_spaces=False)  # an ablation is a field override

Both sides are normalized under the named mode and the result records which protocol produced it. Tokenization is a whitespace split. The corpus rate is total errors over total reference tokens, never the mean of per-utterance rates, which would weight a three-word clip like a thirty-word one.

More

Why this exists · Measured comparison · Where the rules come from · Review the Urdu rules (no Python needed) · Contributing

The space-repair lexicon and the number tables have not been signed off by a native speaker, so numbers_to_words ships off in every mode.

Citing

@software{urdunorm,
  title  = {urdunorm: Urdu text normalization for reproducible ASR evaluation},
  author = {Hassan Bhatti, Hunzalah},
  year   = {2026},
  doi    = {10.5281/zenodo.21864104},
  url    = {https://github.com/hunzed/urdunorm}
}

Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

urdunorm-0.1.1.tar.gz (126.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

urdunorm-0.1.1-py3-none-any.whl (48.3 kB view details)

Uploaded Python 3

File details

Details for the file urdunorm-0.1.1.tar.gz.

File metadata

  • Download URL: urdunorm-0.1.1.tar.gz
  • Upload date:
  • Size: 126.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for urdunorm-0.1.1.tar.gz
Algorithm Hash digest
SHA256 16db362abb694aa5f5e2cbc133d5d2b3730822e99150a84edf162d057e8d8cb8
MD5 36951c208d29de80d88a9d0c84cf956b
BLAKE2b-256 b4f5f7c012f816cd17083607073e553c0718289f3e43fffd4ca352038c43a1c7

See more details on using hashes here.

Provenance

The following attestation bundles were made for urdunorm-0.1.1.tar.gz:

Publisher: publish.yml on hunzed/urdunorm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file urdunorm-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: urdunorm-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 48.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for urdunorm-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7ec05683b215b509ea9f149c2408076c909f1851d011da0969027bafdc6c66c5
MD5 5834c1cb47add5dcf76f1fc1ce1b5253
BLAKE2b-256 3905f30c8774530000dd1b37b0f735a39b829f09c86740930e2d20b2c381428c

See more details on using hashes here.

Provenance

The following attestation bundles were made for urdunorm-0.1.1-py3-none-any.whl:

Publisher: publish.yml on hunzed/urdunorm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page