Spaces:
Sleeping
Sleeping
Upload 5 files
Browse files- normalizer.py +65 -0
- requirement.txt +5 -0
- simple_test.py +225 -0
- tests.py +0 -0
- utils.py +51 -0
normalizer.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from rules.base import BaseProcessor
|
| 2 |
+
from rules.currency import CurrencyProcessor
|
| 3 |
+
from rules.dates import DateProcessor
|
| 4 |
+
from rules.fraction import FractionProcessor
|
| 5 |
+
from rules.cards import CardNumberProcessor
|
| 6 |
+
from rules.postal_national_id import PostalCodeAndNationalIdProcessor
|
| 7 |
+
from rules.numbers import NumberProcessor
|
| 8 |
+
from rules.phone import PhoneNumberProcessor
|
| 9 |
+
from rules.spaces import CurrencySpaceProcessor
|
| 10 |
+
from rules.symbols import (
|
| 11 |
+
AmpersandProcessor,
|
| 12 |
+
MathOperatorProcessor,
|
| 13 |
+
NegativeSignProcessor,
|
| 14 |
+
RangeProcessor,
|
| 15 |
+
RomanNumeralProcessor,
|
| 16 |
+
)
|
| 17 |
+
from rules.times import TimeProcessor
|
| 18 |
+
from rules.units import UnitProcessor
|
| 19 |
+
from utils import detect_language
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class Normalizer(BaseProcessor):
|
| 23 |
+
def __init__(self):
|
| 24 |
+
super(Normalizer, self).__init__()
|
| 25 |
+
self.text_processors = [
|
| 26 |
+
CurrencySpaceProcessor(),
|
| 27 |
+
CardNumberProcessor(),
|
| 28 |
+
PostalCodeAndNationalIdProcessor(),
|
| 29 |
+
PhoneNumberProcessor(),
|
| 30 |
+
NegativeSignProcessor(),
|
| 31 |
+
RangeProcessor(),
|
| 32 |
+
UnitProcessor(),
|
| 33 |
+
FractionProcessor(),
|
| 34 |
+
RomanNumeralProcessor(),
|
| 35 |
+
AmpersandProcessor(),
|
| 36 |
+
MathOperatorProcessor()
|
| 37 |
+
]
|
| 38 |
+
self.processors = [
|
| 39 |
+
DateProcessor(),
|
| 40 |
+
TimeProcessor(),
|
| 41 |
+
CurrencyProcessor()
|
| 42 |
+
]
|
| 43 |
+
# Runs last, on whatever number is still left as digits.
|
| 44 |
+
self.number_processor = NumberProcessor()
|
| 45 |
+
|
| 46 |
+
def process(self, text:str) -> str:
|
| 47 |
+
language = detect_language(text)
|
| 48 |
+
for text_processor in self.text_processors:
|
| 49 |
+
text = text_processor.process(text, language=language)
|
| 50 |
+
# A processor may have rewritten symbols into words (`5 km`).
|
| 51 |
+
language = detect_language(text)
|
| 52 |
+
for processor in self.processors:
|
| 53 |
+
text = self._apply_a_processor(text=text, processor=processor, language=language)
|
| 54 |
+
return self.number_processor.process(text, language=detect_language(text))
|
| 55 |
+
|
| 56 |
+
@staticmethod
|
| 57 |
+
def _apply_a_processor(text:str, processor:BaseProcessor, language:str) -> str:
|
| 58 |
+
words = text.split()
|
| 59 |
+
processed = []
|
| 60 |
+
|
| 61 |
+
for word in words:
|
| 62 |
+
word = word.strip()
|
| 63 |
+
processed.append(processor.process(word, language=language))
|
| 64 |
+
|
| 65 |
+
return ' '.join(processed)
|
requirement.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
num2words==0.5.14
|
| 2 |
+
persiantools==6.2.0
|
| 3 |
+
num2fawords==1.1
|
| 4 |
+
dataparser==0.0.2
|
| 5 |
+
dateparser==1.4.3
|
simple_test.py
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from normalizer import Normalizer
|
| 2 |
+
|
| 3 |
+
def test_currency_normalization():
|
| 4 |
+
n = Normalizer()
|
| 5 |
+
|
| 6 |
+
assert n.process("من امروز ۳$ دارم") == "من امروز سه دلار دارم"
|
| 7 |
+
assert n.process("من امروز 3$ دارم") == "من امروز سه دلار دارم"
|
| 8 |
+
assert n.process("من امروز 1 $ دارم") == "من امروز یک دلار دارم"
|
| 9 |
+
assert n.process("من امروز 12.4$ دارم") == "من امروز دوازده دلار و چهل سنت دارم"
|
| 10 |
+
assert n.process("من امروز 12.۴$ دارم") == "من امروز دوازده دلار و چهل سنت دارم"
|
| 11 |
+
assert n.process("من امروز 125.۴3$ دارم") == "من امروز یکصد و بیست و پنج دلار و چهل و سه سنت دارم"
|
| 12 |
+
assert n.process("من امروز 12.۴€ دارم") == "من امروز دوازده یورو و چهل سنت دارم"
|
| 13 |
+
assert n.process("من امروز 1001.۴€ و 5۲.4$ دارم") == "من امروز یک هزار و یک یورو و چهل سنت و پنجاه و دو دلار و چهل سنت دارم"
|
| 14 |
+
|
| 15 |
+
assert n.process("I have 3$") == "I have three dollars"
|
| 16 |
+
assert n.process("I have ۳$.") == "I have three dollars."
|
| 17 |
+
assert n.process("I have 1$") == "I have one dollar"
|
| 18 |
+
assert n.process("I have 1 $") == "I have one dollar"
|
| 19 |
+
assert n.process("I have 2.5$") == "I have two dollars and fifty cents"
|
| 20 |
+
assert n.process("I have ۲.۵$") == "I have two dollars and fifty cents"
|
| 21 |
+
assert n.process("I have 2.۵$") == "I have two dollars and fifty cents"
|
| 22 |
+
assert n.process("I have ۱.1$.") == "I have one dollar and ten cents."
|
| 23 |
+
assert n.process("I have 3$ and 1 €") == "I have three dollars and one euro"
|
| 24 |
+
assert n.process("I have 3.9$ and 1.3€ and 12.۳3 £.") == (
|
| 25 |
+
"I have three dollars and ninety cents and one euro and thirty cents "
|
| 26 |
+
"and twelve pounds and thirty-three pence."
|
| 27 |
+
)
|
| 28 |
+
assert n.process("1000$") == "one thousand dollars"
|
| 29 |
+
assert n.process("1,000$") == "one thousand dollars"
|
| 30 |
+
assert n.process("1000 $") == "one thousand dollars"
|
| 31 |
+
assert n.process("1,000,001 €") == "one million and one euros"
|
| 32 |
+
assert n.process("۱۰۰۰$") == "یک هزار دلار"
|
| 33 |
+
assert n.process("۱۰۰۱ $") == "یک هزار و یک دلار"
|
| 34 |
+
|
| 35 |
+
print("✅ All currency normalization tests passed successfully!")
|
| 36 |
+
#----------------------------------------------------------------------------------------------------------------------------
|
| 37 |
+
def test_unit_normalization():
|
| 38 |
+
n = Normalizer()
|
| 39 |
+
|
| 40 |
+
assert n.process("وزن او ۷۵kg است") == "وزن او هفتاد و پنج کیلوگرم است"
|
| 41 |
+
assert n.process("وزن او 75kg است") == "وزن او هفتاد و پنج کیلوگرم است"
|
| 42 |
+
assert n.process("دمای هوا ۷۷°F است") == "دمای هوا هفتاد و هفت درجه فارنهایت است"
|
| 43 |
+
assert n.process("از اینجا تا آنجا ۱۰۰۰.۵m فاصله است") == "از اینجا تا آنجا یک هزار متر و پنجاه سانتیمتر فاصله است"
|
| 44 |
+
assert n.process("I ran 5km today") == "I ran five kilometres today"
|
| 45 |
+
assert n.process("It is 2۵°C outside") == "It is twenty-five degrees Celsius outside"
|
| 46 |
+
assert n.process("The car goes 60 km/h") == "The car goes sixty kilometres per hour"
|
| 47 |
+
assert n.process("1000m") == "one thousand metres"
|
| 48 |
+
assert n.process("۲۳۰۰m") == "دو هزار و سیصد متر"
|
| 49 |
+
assert n.process("۱.۲۳۴ m") == "یک متر و بیست و سه سانتیمتر و چهار میلیمتر"
|
| 50 |
+
assert n.process("26°C") == "twenty-six degrees Celsius"
|
| 51 |
+
assert n.process("۲۶ °C") == "بیست و شش درجه سانتیگراد"
|
| 52 |
+
assert n.process("۲۴ °F") == "بیست و چهار درجه فارنهایت"
|
| 53 |
+
assert n.process("۷۰ km/h") == "هفتاد کیلومتر بر ساعت"
|
| 54 |
+
assert n.process("۳.۵ L") == "سه لیتر و پانصد میلیلیتر"
|
| 55 |
+
assert n.process("۸ oz") == "هشت اونس"
|
| 56 |
+
assert n.process("۳.۵ sec") == "سه ثانیه و پانصد میلیثانیه"
|
| 57 |
+
assert n.process("۳.۵ min") == "سه دقیقه و سی ثانیه"
|
| 58 |
+
assert n.process("3.5hour") == "three hours and thirty minutes"
|
| 59 |
+
assert n.process("3.51 hour") == "three hours, thirty minutes and thirty-six seconds"
|
| 60 |
+
assert n.process("3.512 hour") == "three hours, thirty minutes, forty-three seconds and two hundred milliseconds"
|
| 61 |
+
assert n.process("۳.۵۱۲ hour") == "سه ساعت و سی دقیقه و چهل و سه ثانیه و دویست میلیثانیه"
|
| 62 |
+
assert n.process("10.5 days") == "ten days and twelve hours"
|
| 63 |
+
assert n.process("۱,۰۰۰,۰۰۰ hour") == "یک میلیون ساعت"
|
| 64 |
+
assert n.process("5 %") == "five percent"
|
| 65 |
+
assert n.process("%5") == "five percent"
|
| 66 |
+
assert n.process("٪۲۰") == "بیست درصد"
|
| 67 |
+
assert n.process("20 % cm") == "twenty percent centimetre"
|
| 68 |
+
assert n.process("۲۰% cm") == "بیست درصد سانتیمتر"
|
| 69 |
+
assert n.process("۲۰٪ cm") == "بیست درصد سانتیمتر"
|
| 70 |
+
assert n.process("٪۲۰ cm") == "بیست درصد سانتیمتر"
|
| 71 |
+
assert n.process("٪ ۲۰ cm.") == "بیست درصد سانتیمتر."
|
| 72 |
+
assert n.process("% ۲۰ cm.") == "بیست درصد سانتیمتر."
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
print("✅ All unit normalization tests passed successfully!")
|
| 76 |
+
#----------------------------------------------------------------------------------------------------------------------------
|
| 77 |
+
def test_fraction_normalization():
|
| 78 |
+
n = Normalizer()
|
| 79 |
+
|
| 80 |
+
assert n.process("1/3") == "one third"
|
| 81 |
+
assert n.process("1000000/3") == "one million thirds"
|
| 82 |
+
assert n.process("۱/۳") == "یک سوم"
|
| 83 |
+
assert n.process("۱ ۱/۳") == "یک و یک سوم"
|
| 84 |
+
assert n.process("1/2 kg") == "one half kilogram"
|
| 85 |
+
assert n.process("1000/2 kg") == "one thousand halves kilograms"
|
| 86 |
+
assert n.process("1,000,000/2 sec") == "one million halves seconds"
|
| 87 |
+
assert n.process("1,000,000/3 sec") == "one million thirds seconds"
|
| 88 |
+
assert n.process("۱,۵۰۰,۰۰۰/۳ hour") == "یک میلیون و پانصد هزار سوم ساعت"
|
| 89 |
+
assert n.process("۶/۵ sec") == "شش پنجم ثانیه"
|
| 90 |
+
assert n.process("۷/۹۰ km/h") == "هفت نودم کیلومتر بر ساعت"
|
| 91 |
+
assert n.process("۷.۹۰ km/h") == "هفت و نه دهم کیلومتر بر ساعت"
|
| 92 |
+
assert n.process("۱۵ ۱۲/۲۳ min") == "پانزده و دوازده بیست و سوم دقیقه"
|
| 93 |
+
assert n.process("1 100/2 %") == "one and one hundred halves percent"
|
| 94 |
+
assert n.process("۱/۲ ٪") == "یک دوم درصد"
|
| 95 |
+
assert n.process("1 5,000/2000% cm") == "one and five thousand two thousandths percent centimetre"
|
| 96 |
+
assert n.process("۲/۱۰٪ cm") == "دو دهم درصد سانتیمتر"
|
| 97 |
+
assert n.process("3/4 km/h") == "three quarters kilometre per hour"
|
| 98 |
+
assert n.process("1½ kg") == "one and one half kilograms"
|
| 99 |
+
assert n.process("۵½ kg") == "پنج و یک دوم کیلوگرم"
|
| 100 |
+
|
| 101 |
+
print("✅ All fraction normalization tests passed successfully!")
|
| 102 |
+
#----------------------------------------------------------------------------------------------------------------------------
|
| 103 |
+
def test_symbol_normalization():
|
| 104 |
+
n = Normalizer()
|
| 105 |
+
|
| 106 |
+
assert n.process("علی & محسن") == "علی و محسن"
|
| 107 |
+
assert n.process("Ali & Mohsen") == "Ali and Mohsen"
|
| 108 |
+
assert n.process("R&D") == "R and D"
|
| 109 |
+
assert n.process("Tom &Jerry") == "Tom and Jerry"
|
| 110 |
+
assert n.process("4 & 5") == "four and five"
|
| 111 |
+
assert n.process("۴ & ۵") == "چهار و پنج"
|
| 112 |
+
assert n.process("3/4 & 7/3") == "three quarters and seven thirds"
|
| 113 |
+
assert n.process("۱/۲ & ۳/۲") == "یک دوم و سه دوم"
|
| 114 |
+
assert n.process("Farzin & 2 friends") == "Farzin and two friends"
|
| 115 |
+
assert n.process("Chapter V.") == "Chapter five."
|
| 116 |
+
assert n.process("Mohsen V.") == "Mohsen V."
|
| 117 |
+
assert n.process("II & IV") == "two and four"
|
| 118 |
+
assert n.process("3$ & 4€") == "three dollars and four euros"
|
| 119 |
+
assert n.process("بخش V را بخوان") == "بخش پنج را بخوان"
|
| 120 |
+
|
| 121 |
+
assert n.process("- 2 kg") == "negative two kilograms"
|
| 122 |
+
assert n.process("3+4") == "three plus four"
|
| 123 |
+
assert n.process("3×4") == "three times four"
|
| 124 |
+
assert n.process("3 × 4=12.") == "three times four equals twelve."
|
| 125 |
+
assert n.process("8 ÷ 2") == "eight divided by two"
|
| 126 |
+
assert n.process("۸ ÷ ۲") == "هشت تقسیم بر دو"
|
| 127 |
+
assert n.process("۸ × ۲ = 16") == "هشت ضربدر دو مساوی است با شانزده"
|
| 128 |
+
assert n.process("۸ * ۲ = 16") == "هشت ضربدر دو مساوی است با شانزده"
|
| 129 |
+
assert n.process("5 - 3 = 2") == "five minus three equals two"
|
| 130 |
+
assert n.process("5,000 - 3000 = 2000") == "five thousand minus three thousand equals two thousand"
|
| 131 |
+
assert n.process("۵ - ۳ = ۲") == "پنج منهای سه مساوی است با دو"
|
| 132 |
+
assert n.process("5kg + 3kg = 8kg") == "five kilograms plus three kilograms equals eight kilograms"
|
| 133 |
+
assert n.process("Tom + Jerry") == "Tom plus Jerry"
|
| 134 |
+
|
| 135 |
+
assert n.process("5 - 10") == "five to ten"
|
| 136 |
+
assert n.process("1/2 - 3/4") == "one half to three quarters"
|
| 137 |
+
assert n.process("5kg - 10kg") == "five kilograms to ten kilograms"
|
| 138 |
+
assert n.process("5% - 10%") == "five percent to ten percent"
|
| 139 |
+
assert n.process("1990 - 2000") == "one thousand, nine hundred and ninety to two thousand"
|
| 140 |
+
|
| 141 |
+
assert n.process('3 "m"') == 'three "metres"'
|
| 142 |
+
assert n.process('3 (kg)') == 'three (kilograms)'
|
| 143 |
+
assert n.process('3 {kg}') == 'three {kilograms}'
|
| 144 |
+
assert n.process('3 [kg]') == 'three [kilograms]'
|
| 145 |
+
assert n.process('(3) + (4)') == '(three) plus (four)'
|
| 146 |
+
assert n.process('3 $ + [4 oz]') == 'three dollars plus [four ounces]'
|
| 147 |
+
assert n.process('[3]-[5]') == '[three] to [five]'
|
| 148 |
+
assert n.process('[۳] - ۵') == '[سه] تا پنج'
|
| 149 |
+
|
| 150 |
+
print("✅ All symbol normalization tests passed successfully!")
|
| 151 |
+
#----------------------------------------------------------------------------------------------------------------------------
|
| 152 |
+
def test_phone_normalization():
|
| 153 |
+
n = Normalizer()
|
| 154 |
+
|
| 155 |
+
assert n.process("۰۹۱۵۶۴۸۶۳۲۰") == "صفر نهصد و پانزده، ششصد و چهل و هشت، شصت و سه، بیست"
|
| 156 |
+
assert n.process("۰۹۱۵-۶۴۸۶۳۲۰") == "صفر نهصد و پانزده، ششصد و چهل و هشت، شصت و سه، بیست"
|
| 157 |
+
assert n.process("+۹۸۹۱۵۶۴۸۶۳۲۰") == "مثبت نود و هشت، نهصد و پانزده، ششصد و چهل و هشت، شصت و سه، بیست"
|
| 158 |
+
assert n.process("(+۹۸۹۱۵) ۶۴۸۶۳۲۰") == "(مثبت نود و هشت، نهصد و پانزده)، ششصد و چهل و هشت، شصت و سه، بیست"
|
| 159 |
+
assert n.process("۰۲۱-۸۸۵۲۳۰۰۶") == "صفر بیست و یک، هشتاد و هشت، پنجاه و دو، سی، صفر شش"
|
| 160 |
+
assert n.process("(۰۲۱) ۸۸۵۲۳۰۰۶") == "(صفر بیست و یک)، هشتاد و هشت، پنجاه و دو، سی، صفر شش"
|
| 161 |
+
assert n.process("(۰۲۱)۸۸۵۲۳۰۰۶") == "(صفر بیست و یک)، هشتاد و هشت، پنجاه و دو، سی، صفر شش"
|
| 162 |
+
assert n.process("۰۰۱-۸۸۵۲۳۰۰۶") == "دو صفر یک، هشتاد و هشت، پنجاه و دو، سی، صفر شش"
|
| 163 |
+
assert n.process("09156486320") == "zero nine one five, six four eight, six three, two zero"
|
| 164 |
+
assert n.process("0915-6486320") == "zero nine one five, six four eight, six three, two zero"
|
| 165 |
+
assert n.process("(0915) 6486320") == "(zero nine one five), six four eight, six three, two zero"
|
| 166 |
+
assert n.process("(0915)6486320") == "(zero nine one five), six four eight, six three, two zero"
|
| 167 |
+
assert n.process("+989156486320") == "plus nine eight, nine one five, six four eight, six three, two zero"
|
| 168 |
+
assert n.process("(+98915) 6486320") == "(plus nine eight, nine one five), six four eight, six three, two zero"
|
| 169 |
+
assert n.process("02188523006") == "zero two one, eight eight, five two, three zero, zero six"
|
| 170 |
+
assert n.process("021-88523006") == "zero two one, eight eight, five two, three zero, zero six"
|
| 171 |
+
assert n.process("Call 1-800-555-1234") == "Call one, eight zero zero, five five five, one two three four"
|
| 172 |
+
assert n.process("زنگ بزن به 09356486320") == "زنگ بزن به صفر نهصد و سی و پنج، ششصد و چهل و هشت، شصت و سه، بیست"
|
| 173 |
+
|
| 174 |
+
print("✅ All phone normalization tests passed successfully!")
|
| 175 |
+
#----------------------------------------------------------------------------------------------------------------------------
|
| 176 |
+
def test_card_normalization():
|
| 177 |
+
n = Normalizer()
|
| 178 |
+
|
| 179 |
+
assert n.process("6219-8619-1635-6362") == "sixty-two, nineteen - eighty-six, nineteen - sixteen, thirty-five - sixty-three, sixty-two"
|
| 180 |
+
assert n.process("6200-8619-1635-6305") == "sixty-two, double zero - eighty-six, nineteen - sixteen, thirty-five - sixty-three, oh five"
|
| 181 |
+
assert n.process("6200861916356305") == "sixty-two, double zero - eighty-six, nineteen - sixteen, thirty-five - sixty-three, oh five"
|
| 182 |
+
assert n.process("۶۲۱۹-۸۶۱۹-۱۶۳۵-۶۳۶۲") == "شصت و دو، نوزده - هشتاد و شش، نوزده - شانزده، سی و پنج - شصت و سه، شصت و دو"
|
| 183 |
+
assert n.process("۶۲۰۰-۸۶۱۹-۱۶۳۵-۶۳۰۵") == "شصت و دو، دو صفر - هشتاد و شش، نوزده - شانزده، سی و پنج - شصت و سه، صفر پنج"
|
| 184 |
+
assert n.process("۶۲۰۰۸۶۱۹۱۶۳۵۶۳۰۵") == "شصت و دو، دو صفر - هشتاد و شش، نوزده - شانزده، سی و پنج - شصت و سه، صفر پنج"
|
| 185 |
+
assert n.process("شماره کارت من رو یادداشت کنین: 6200861916356305") == "شماره کارت من رو یادداشت کنین: شصت و دو، دو صفر - هشتاد و شش، نوزده - شانزده، سی و پنج - شصت و سه، صفر پنج"
|
| 186 |
+
|
| 187 |
+
print("✅ All card normalization tests passed successfully!")
|
| 188 |
+
#----------------------------------------------------------------------------------------------------------------------------
|
| 189 |
+
def test_postal_nationalId_normalization():
|
| 190 |
+
n = Normalizer()
|
| 191 |
+
|
| 192 |
+
assert n.process("1514717118") == "fifteen, fourteen, seventy-one, seventy-one, eighteen"
|
| 193 |
+
assert n.process("15147-17118") == "fifteen, fourteen, seventy-one, seventy-one, eighteen"
|
| 194 |
+
assert n.process("۱۵۱۴۷۱۷۱۱۸") == "پانزده، چهارده، هفتاد و یک، هفتاد و یک، هجده"
|
| 195 |
+
assert n.process("۱۵۱۴۷-۱۷۱۱۸") == "پانزده، چهارده، هفتاد و یک، هفتاد و یک، هجده"
|
| 196 |
+
|
| 197 |
+
assert n.process("0010062637") == "double zero, ten, oh six, twenty-six, thirty-seven"
|
| 198 |
+
assert n.process("[0010062637]") == "[double zero, ten, oh six, twenty-six, thirty-seven]"
|
| 199 |
+
assert n.process("۰۰۱۰۰۶۲۶۳۷") == "دو صفر، ده، صفر شش، بیست و شش، سی و هفت"
|
| 200 |
+
|
| 201 |
+
print("✅ All postal and national id normalization tests passed successfully!")
|
| 202 |
+
|
| 203 |
+
#----------------------------------------------------------------------------------------------------------------------------
|
| 204 |
+
def test_plain_number_normalization():
|
| 205 |
+
n = Normalizer()
|
| 206 |
+
|
| 207 |
+
assert n.process("۳.۵") == "سه و پنج دهم"
|
| 208 |
+
assert n.process("3.5") == "three point five"
|
| 209 |
+
assert n.process("من ۲۰ سیب دارم") == "من بیست سیب دارم"
|
| 210 |
+
assert n.process("۱۴۰۳") == "یک هزار و چهارصد و سه"
|
| 211 |
+
assert n.process("سال ۱۴۰۳") == "سال هزار و چهارصد و سه"
|
| 212 |
+
assert n.process("4338135") == "four million, three hundred and thirty-eight thousand, one hundred and thirty-five"
|
| 213 |
+
|
| 214 |
+
print("✅ All plain number normalization tests passed successfully!")
|
| 215 |
+
|
| 216 |
+
#----------------------------------------------------------------------------------------------------------------------------
|
| 217 |
+
if __name__ == "__main__":
|
| 218 |
+
test_currency_normalization()
|
| 219 |
+
test_unit_normalization()
|
| 220 |
+
test_fraction_normalization()
|
| 221 |
+
test_symbol_normalization()
|
| 222 |
+
test_phone_normalization()
|
| 223 |
+
test_card_normalization()
|
| 224 |
+
test_postal_nationalId_normalization()
|
| 225 |
+
test_plain_number_normalization()
|
tests.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
utils.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import re
|
| 2 |
+
|
| 3 |
+
NO_LETTERS = "Unknown / No letters found"
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def detect_language(text: str) -> str:
|
| 7 |
+
cleaned_text = re.sub(r'[\s\d\W_]+', '', text)
|
| 8 |
+
|
| 9 |
+
if not cleaned_text:
|
| 10 |
+
return NO_LETTERS
|
| 11 |
+
|
| 12 |
+
persian_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]')
|
| 13 |
+
english_pattern = re.compile(r'[a-zA-Z]')
|
| 14 |
+
|
| 15 |
+
persian_count = len(persian_pattern.findall(cleaned_text))
|
| 16 |
+
english_count = len(english_pattern.findall(cleaned_text))
|
| 17 |
+
|
| 18 |
+
if persian_count > english_count:
|
| 19 |
+
return "fa"
|
| 20 |
+
elif english_count > persian_count:
|
| 21 |
+
return "en"
|
| 22 |
+
else:
|
| 23 |
+
return "mixed"
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def detect_digit_language(text: str):
|
| 27 |
+
"""Guesses the language from the digits alone: Persian digits -> "fa",
|
| 28 |
+
ASCII digits -> "en", no digits -> None. Used when a text has no letters."""
|
| 29 |
+
if re.search(r'[\u06F0-\u06F9\u0660-\u0669]', text):
|
| 30 |
+
return "fa"
|
| 31 |
+
if re.search(r'[0-9]', text):
|
| 32 |
+
return "en"
|
| 33 |
+
return None
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def convert_fa_num_to_en(text:str) -> str:
|
| 37 |
+
fa_to_en = {
|
| 38 |
+
'۰':'0',
|
| 39 |
+
'۱':'1',
|
| 40 |
+
'۲':'2',
|
| 41 |
+
'۳':'3',
|
| 42 |
+
'۴':'4',
|
| 43 |
+
'۵':'5',
|
| 44 |
+
'۶':'6',
|
| 45 |
+
'۷':'7',
|
| 46 |
+
'۸':'8',
|
| 47 |
+
'۹':'9',
|
| 48 |
+
}
|
| 49 |
+
for k, v in fa_to_en.items():
|
| 50 |
+
text = text.replace(k, v)
|
| 51 |
+
return text
|