ArabicNormalizer & NormalizingChunkerWrapper
On this page
Module: chunks.arabic_preprocessor
Import: from zerda.chunks import ArabicNormalizer, NormalizingChunkerWrapper, NormalizerConfig
Table of Contents
NormalizerConfig
@dataclass
class NormalizerConfig:
normalize_alef: bool = True
normalize_teh_marbuta: bool = True
normalize_yeh: bool = True
remove_diacritics: bool = True
remove_tatweel: bool = True
normalize_hamza: bool = True
remove_punctuation: bool = False
normalize_numbers: bool = False
max_repeated_chars: int = 2
fix_spacing: bool = True
language: str = "arabic"
All flags are True by default except remove_punctuation and normalize_numbers, preserving text readability while normalizing orthographic variants.
ArabicNormalizer
Purpose
ArabicNormalizer is a preprocessing pipeline that standardizes Arabic text orthography before chunking. It eliminates spelling variations that would otherwise cause the same word to be treated as distinct tokens.
Typical use: wrap with NormalizingChunkerWrapper so normalization runs transparently before any chunker.
ArabicNormalizer Constructor
ArabicNormalizer(
config: Optional[NormalizerConfig] = None,
)
If config is None, NormalizerConfig() defaults are used.
ArabicNormalizer Methods
normalize(text: str) → str
Applies the full normalization pipeline.
normalizer = ArabicNormalizer()
clean = normalizer.normalize("الأُسْتاذُ يُدرِّسُ اللُّغةَ")
print(clean) # "الاستاذ يدرس اللغه"
normalize_batch(texts: List[str]) → List[str]
Applies normalize() to each text in the list.
cleaned = normalizer.normalize_batch(["مرحباً", "السَّلامُ"])
get_normalization_stats(original: str, normalized: str) → dict
Returns statistics comparing before/after normalization:
{
"original_length": 42,
"normalized_length": 38,
"reduction_ratio": 0.095,
"chars_removed": 4,
}
Normalization Pipeline
Steps execute in this exact order:
1. normalize_alef → إأآأ → ا
2. normalize_teh_marbuta → ة → ه
3. normalize_yeh → يى → ي
4. normalize_hamza → ؤئ → ء
5. remove_tatweel → remove ـ
6. remove_diacritics → remove U+064B–U+065F harakat
7. normalize_numbers → ٠-٩ → 0-9 (if enabled)
8. remove_punctuation → strip .,!?،؛ (if enabled)
9. max_repeated_chars → collapse runs
10. fix_spacing → normalize whitespace
NormalizingChunkerWrapper
Purpose
NormalizingChunkerWrapper is a decorator that transparently applies ArabicNormalizer.normalize() to the input text before passing it to any BaseChunker. The resulting chunks contain normalized text.
NormalizingChunkerWrapper Constructor
NormalizingChunkerWrapper(
chunker: BaseChunker,
normalizer: Optional[ArabicNormalizer] = None,
config: Optional[NormalizerConfig] = None,
)
NormalizingChunkerWrapper Methods
chunk(text, doc_id="", source="") → List[DocumentChunk]
- Calls
self.normalizer.normalize(text). - Passes normalized text to
self.chunker.chunk(...). - Returns results unchanged.
chunk_documents(documents) → List[DocumentChunk]
Normalizes each document's page_content then calls the wrapped chunker.
Examples
Normalizer Standalone
from zerda.chunks import ArabicNormalizer, NormalizerConfig
config = NormalizerConfig(
normalize_alef=True,
remove_diacritics=True,
normalize_numbers=True,
)
normalizer = ArabicNormalizer(config=config)
clean = normalizer.normalize("الأُسْتاذُ يُدرِّسُ ٣ طلاب")
print(clean) # "الاستاذ يدرس 3 طلاب"
Wrapped Chunker
from zerda.chunks import (
ArabicNormalizer, NormalizingChunkerWrapper,
ArabicTextChunker, NormalizerConfig,
)
normalizer = ArabicNormalizer()
chunker = ArabicTextChunker(chunk_size=400, use_semantic_chunking=False)
wrapper = NormalizingChunkerWrapper(chunker, normalizer=normalizer)
chunks = wrapper.chunk(raw_arabic_text, doc_id="doc_1", source="ocr_scan.pdf")
for c in chunks:
print(c.text) # normalized text
Custom Normalization
config = NormalizerConfig(
remove_diacritics=True,
remove_punctuation=True, # for keyword extraction
normalize_numbers=True,
max_repeated_chars=1, # collapse all repetitions
)
normalizer = ArabicNormalizer(config=config)
Stats
normalizer = ArabicNormalizer()
original = "الأُسْتاذُ الكَريمُ"
normalized = normalizer.normalize(original)
stats = normalizer.get_normalization_stats(original, normalized)
print(stats)
# {'original_length': 18, 'normalized_length': 13, 'reduction_ratio': 0.278, 'chars_removed': 5}
Wrapping MultilanguageTextChunker
from zerda.chunks import MultilanguageTextChunker, NormalizingChunkerWrapper, ArabicNormalizer
wrapper = NormalizingChunkerWrapper(
MultilanguageTextChunker(language="arabic"),
normalizer=ArabicNormalizer(),
)
chunks = wrapper.chunk(text)