dv-normalizer 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dv-normalizer-0.1.0/LICENCE +21 -0
- dv-normalizer-0.1.0/PKG-INFO +100 -0
- dv-normalizer-0.1.0/README.md +90 -0
- dv-normalizer-0.1.0/dv_normalize/__init__.py +4 -0
- dv-normalizer-0.1.0/dv_normalize/dv_num.py +169 -0
- dv-normalizer-0.1.0/dv_normalize/dv_sentence.py +133 -0
- dv-normalizer-0.1.0/dv_normalizer.egg-info/PKG-INFO +100 -0
- dv-normalizer-0.1.0/dv_normalizer.egg-info/SOURCES.txt +11 -0
- dv-normalizer-0.1.0/dv_normalizer.egg-info/dependency_links.txt +1 -0
- dv-normalizer-0.1.0/dv_normalizer.egg-info/top_level.txt +1 -0
- dv-normalizer-0.1.0/pyproject.toml +6 -0
- dv-normalizer-0.1.0/setup.cfg +4 -0
- dv-normalizer-0.1.0/setup.py +20 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: dv-normalizer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python library for normalizing Dhivehi text and converting numbers to Dhivehi text format, supporting written, spoken and year forms
|
|
5
|
+
Author: Alakxender
|
|
6
|
+
Author-email: alakxender@gmail.com
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENCE
|
|
10
|
+
|
|
11
|
+
# dv-normalize
|
|
12
|
+
|
|
13
|
+
A Python library for normalizing Dhivehi text by converting numbers to Dhivehi and standardizing sentence endings.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- Converts numbers to Dhivehi text (both written and spoken forms)
|
|
18
|
+
- Handles years (when followed by ވަނަ)
|
|
19
|
+
- Handles decimal numbers
|
|
20
|
+
- Normalizes formal sentence endings to colloquial form
|
|
21
|
+
- Preserves proper spacing and punctuation
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install dv-normalize
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
There are two main functions in this library:
|
|
32
|
+
|
|
33
|
+
1. `int_to_dv` - This function converts numbers to Dhivehi text in written form.
|
|
34
|
+
2. `spoken_dv` - This function converts dhivehi text to spoken form.
|
|
35
|
+
|
|
36
|
+
### Written form
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
|
|
40
|
+
## test case for int_to_dv
|
|
41
|
+
|
|
42
|
+
from dv_normalize.dv_num import int_to_dv
|
|
43
|
+
|
|
44
|
+
def main():
|
|
45
|
+
while True:
|
|
46
|
+
try:
|
|
47
|
+
num = input("Enter a number (0 to trillion) or 'q' to exit: ")
|
|
48
|
+
if num.lower() == 'q':
|
|
49
|
+
break
|
|
50
|
+
|
|
51
|
+
num = int(num)
|
|
52
|
+
if num < 0:
|
|
53
|
+
print("Please enter a non-negative number")
|
|
54
|
+
continue
|
|
55
|
+
|
|
56
|
+
print(f"{num:,} in Dhivehi:")
|
|
57
|
+
written = int_to_dv(num, is_spoken=False)
|
|
58
|
+
spoken = int_to_dv(num, is_spoken=True)
|
|
59
|
+
year = "Not a valid year format" if num < 1000 or num > 9999 else int_to_dv(num, is_year=True)
|
|
60
|
+
|
|
61
|
+
print(f"Written form: {written}")
|
|
62
|
+
print(f"Spoken form: {spoken}")
|
|
63
|
+
print(f"Year form: {year}")
|
|
64
|
+
|
|
65
|
+
except ValueError:
|
|
66
|
+
print("Please enter a valid number")
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
main()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Spoken form
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from dv_normalize.dv_sentence import spoken_dv
|
|
76
|
+
|
|
77
|
+
# Test cases
|
|
78
|
+
test_cases = [
|
|
79
|
+
"މިއަދު ވަރަށް ފިނިވެއެވެ.", # Verb ending
|
|
80
|
+
"މިއީ ރީތި ފޮތެކެވެ.", # Noun ending
|
|
81
|
+
"އޭނާ ދަނީ ސްކޫލަށެވެ.", # Direction ending
|
|
82
|
+
"1955 މީހުން ތިބެއެވެ.", # Number with ending
|
|
83
|
+
"2024 ވަނަ އަހަރު", # Year
|
|
84
|
+
"12.5 ރުފިޔާ", # Decimal
|
|
85
|
+
"1000 މީހުން", # Regular number
|
|
86
|
+
"މިއީ ރީތި ފޮތެކެވެ.", # Sentence ending
|
|
87
|
+
"އޭނާ ގެއަށެވެ.", # Sentence ending
|
|
88
|
+
"ހާއްސަ އެއްބަސްވުމުގެ ދަށުން އިންޑިއާއިން ރާއްޖެއަށް ވިއްކާ ހަކުރު އޮޅުވާލައިގެން ލަންކާއަށް!", # test sentence
|
|
89
|
+
"އެ އިދާރާއިން ބަލަމުން އަންނަނީ މިދިޔަ މަހުގެ 25 ގައި އެގައުމުން ބޭރު ކުރި 64 ހާސް ޓަނުގެ ހަކުރުގެ ޝިޕްމެންޓެއްގެ މައްސަލަ އެވެ. އެ ޝިޕްމެންޓް އެގައުމުން ބޭރުކުރީ ރާއްޖެ އާއި އިންޑިއާ އާ ދެމެދު ވެފައިވާ ވިޔަފާރީގެ ހާއްސަ އެއްބަސްވުމުގެ ދަށުން ކަނޑައަޅާފައިވާ އަގުތަކުގައި ނަމަވެސް، އެއިން ބައެއް ލަންކާއަށް އެތެރެކުރިން ފަޅާއަރާފައިވާ ކަމަށް އިންޑިއާގެ ބައެއް ނޫސްތަކުގައި ރިފޯޓުކޮށްފައިވެ އެވެ." # test long sentence
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
for test in test_cases:
|
|
93
|
+
print(f"Original: {test}")
|
|
94
|
+
print(f"Normalized: {spoken_dv(test)}\n")
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# dv-normalize
|
|
2
|
+
|
|
3
|
+
A Python library for normalizing Dhivehi text by converting numbers to Dhivehi and standardizing sentence endings.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Converts numbers to Dhivehi text (both written and spoken forms)
|
|
8
|
+
- Handles years (when followed by ވަނަ)
|
|
9
|
+
- Handles decimal numbers
|
|
10
|
+
- Normalizes formal sentence endings to colloquial form
|
|
11
|
+
- Preserves proper spacing and punctuation
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install dv-normalize
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
There are two main functions in this library:
|
|
22
|
+
|
|
23
|
+
1. `int_to_dv` - This function converts numbers to Dhivehi text in written form.
|
|
24
|
+
2. `spoken_dv` - This function converts dhivehi text to spoken form.
|
|
25
|
+
|
|
26
|
+
### Written form
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
|
|
30
|
+
## test case for int_to_dv
|
|
31
|
+
|
|
32
|
+
from dv_normalize.dv_num import int_to_dv
|
|
33
|
+
|
|
34
|
+
def main():
|
|
35
|
+
while True:
|
|
36
|
+
try:
|
|
37
|
+
num = input("Enter a number (0 to trillion) or 'q' to exit: ")
|
|
38
|
+
if num.lower() == 'q':
|
|
39
|
+
break
|
|
40
|
+
|
|
41
|
+
num = int(num)
|
|
42
|
+
if num < 0:
|
|
43
|
+
print("Please enter a non-negative number")
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
print(f"{num:,} in Dhivehi:")
|
|
47
|
+
written = int_to_dv(num, is_spoken=False)
|
|
48
|
+
spoken = int_to_dv(num, is_spoken=True)
|
|
49
|
+
year = "Not a valid year format" if num < 1000 or num > 9999 else int_to_dv(num, is_year=True)
|
|
50
|
+
|
|
51
|
+
print(f"Written form: {written}")
|
|
52
|
+
print(f"Spoken form: {spoken}")
|
|
53
|
+
print(f"Year form: {year}")
|
|
54
|
+
|
|
55
|
+
except ValueError:
|
|
56
|
+
print("Please enter a valid number")
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
main()
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Spoken form
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from dv_normalize.dv_sentence import spoken_dv
|
|
66
|
+
|
|
67
|
+
# Test cases
|
|
68
|
+
test_cases = [
|
|
69
|
+
"މިއަދު ވަރަށް ފިނިވެއެވެ.", # Verb ending
|
|
70
|
+
"މިއީ ރީތި ފޮތެކެވެ.", # Noun ending
|
|
71
|
+
"އޭނާ ދަނީ ސްކޫލަށެވެ.", # Direction ending
|
|
72
|
+
"1955 މީހުން ތިބެއެވެ.", # Number with ending
|
|
73
|
+
"2024 ވަނަ އަހަރު", # Year
|
|
74
|
+
"12.5 ރުފިޔާ", # Decimal
|
|
75
|
+
"1000 މީހުން", # Regular number
|
|
76
|
+
"މިއީ ރީތި ފޮތެކެވެ.", # Sentence ending
|
|
77
|
+
"އޭނާ ގެއަށެވެ.", # Sentence ending
|
|
78
|
+
"ހާއްސަ އެއްބަސްވުމުގެ ދަށުން އިންޑިއާއިން ރާއްޖެއަށް ވިއްކާ ހަކުރު އޮޅުވާލައިގެން ލަންކާއަށް!", # test sentence
|
|
79
|
+
"އެ އިދާރާއިން ބަލަމުން އަންނަނީ މިދިޔަ މަހުގެ 25 ގައި އެގައުމުން ބޭރު ކުރި 64 ހާސް ޓަނުގެ ހަކުރުގެ ޝިޕްމެންޓެއްގެ މައްސަލަ އެވެ. އެ ޝިޕްމެންޓް އެގައުމުން ބޭރުކުރީ ރާއްޖެ އާއި އިންޑިއާ އާ ދެމެދު ވެފައިވާ ވިޔަފާރީގެ ހާއްސަ އެއްބަސްވުމުގެ ދަށުން ކަނޑައަޅާފައިވާ އަގުތަކުގައި ނަމަވެސް، އެއިން ބައެއް ލަންކާއަށް އެތެރެކުރިން ފަޅާއަރާފައިވާ ކަމަށް އިންޑިއާގެ ބައެއް ނޫސްތަކުގައި ރިފޯޓުކޮށްފައިވެ އެވެ." # test long sentence
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
for test in test_cases:
|
|
83
|
+
print(f"Original: {test}")
|
|
84
|
+
print(f"Normalized: {spoken_dv(test)}\n")
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
def int_to_dv(num, thousands=False, is_spoken=False, is_year=False):
|
|
2
|
+
# Dictionary mapping numbers to their Dhivehi representations
|
|
3
|
+
# Format: [written_form, spoken_form]
|
|
4
|
+
d = {
|
|
5
|
+
0: ["ސުމެއް", "ސުމެއް"],
|
|
6
|
+
1: ["އެއް", "އެކެއް"],
|
|
7
|
+
2: ["ދެ", "ދޭއް"],
|
|
8
|
+
3: ["ތިން", "ތިނެއް"],
|
|
9
|
+
4: ["ހަތަރު", "ހަތަރެއް"],
|
|
10
|
+
5: ["ފަސް", "ފަހެއް"],
|
|
11
|
+
6: ["ހަ", "ހައެއް"],
|
|
12
|
+
7: ["ހަތް", "ހަތެއް"],
|
|
13
|
+
8: ["އަށް", "އަށެއް"],
|
|
14
|
+
9: ["ނުވަ", "ނުވައެއް"],
|
|
15
|
+
10: ["ދިހަ", "ދިހައެއް"],
|
|
16
|
+
11: ["އެގާރަ", "އެގާރަ"],
|
|
17
|
+
12: ["ބާރަ", "ބާރަ"],
|
|
18
|
+
13: ["ތޭރަ", "ތޭރަ"],
|
|
19
|
+
14: ["ސާދަ", "ސާދަ"],
|
|
20
|
+
15: ["ފަނަރަ", "ފަނަރަ"],
|
|
21
|
+
16: ["ސޯޅަ", "ސޯޅަ"],
|
|
22
|
+
17: ["ސަތާރަ", "ސަތާރަ"],
|
|
23
|
+
18: ["އަށާރަ", "އަށާރަ"],
|
|
24
|
+
19: ["ނަވާރަ", "ނަވާރަ"],
|
|
25
|
+
20: ["ވިހި", "ވިހި"],
|
|
26
|
+
30: ["ތިރީސް", "ތިރީސް"],
|
|
27
|
+
40: ["ސާޅީސް", "ސާޅީސް"],
|
|
28
|
+
50: ["ފަންސާސް", "ފަންސާސް"],
|
|
29
|
+
60: ["ފަސްދޮޅަސް", "ފަސްދޮޅަސް"],
|
|
30
|
+
70: ["ހައްދިހަ", "ހައްދިހަ"],
|
|
31
|
+
80: ["އައްޑިހަ", "އައްޑިހަ"],
|
|
32
|
+
90: ["ނުވަދިހަ", "ނުވަދިހަ"]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Map for numbers before ހާސް
|
|
36
|
+
haas_map = {
|
|
37
|
+
"އެކެއް": "އެއް",
|
|
38
|
+
"ދޭއް": "ދެ",
|
|
39
|
+
"ތިނެއް": "ތިން",
|
|
40
|
+
"ހަތަރެއް": "ހަތަރު",
|
|
41
|
+
"ފަހެއް": "ފަސް",
|
|
42
|
+
"ހައެއް": "ހަ",
|
|
43
|
+
"ހަތެއް": "ހަތް",
|
|
44
|
+
"އަށެއް": "އަށް",
|
|
45
|
+
"ނުވައެއް": "ނުވަ"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Constants for large numbers
|
|
49
|
+
k = 1000
|
|
50
|
+
m = k * 1000
|
|
51
|
+
b = m * 1000
|
|
52
|
+
t = b * 1000
|
|
53
|
+
|
|
54
|
+
if num < 0:
|
|
55
|
+
return "Invalid number"
|
|
56
|
+
|
|
57
|
+
if num == 0:
|
|
58
|
+
return "ސުމެއް"
|
|
59
|
+
|
|
60
|
+
# Special mapping for numbers with ވީސް (20-29)
|
|
61
|
+
special_vis = {
|
|
62
|
+
20: "ވީސް",
|
|
63
|
+
21: "އެކާވީސް",
|
|
64
|
+
22: "ބާވީސް",
|
|
65
|
+
23: "ތޭވީސް",
|
|
66
|
+
24: "ސައްވީސް",
|
|
67
|
+
25: "ފަންސަވީސް",
|
|
68
|
+
26: "ސައްބީސް",
|
|
69
|
+
27: "ހަތާވީސް",
|
|
70
|
+
28: "އަށާވީސް",
|
|
71
|
+
29: "ނަވާވީސް"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Special handling for years (1000-9999)
|
|
75
|
+
if is_year and 1000 <= num <= 9999:
|
|
76
|
+
millennium = num // 1000
|
|
77
|
+
last_two_digits = num % 100
|
|
78
|
+
|
|
79
|
+
millennium_text = f"{d[millennium][0]}ހާސް"
|
|
80
|
+
|
|
81
|
+
if last_two_digits == 0:
|
|
82
|
+
return millennium_text
|
|
83
|
+
|
|
84
|
+
# Use special mapping for 20-29
|
|
85
|
+
if last_two_digits in special_vis:
|
|
86
|
+
return f"{millennium_text} {special_vis[last_two_digits]}"
|
|
87
|
+
|
|
88
|
+
# Handle other numbers...
|
|
89
|
+
if last_two_digits in d:
|
|
90
|
+
return f"{millennium_text} {d[last_two_digits][0]}"
|
|
91
|
+
else:
|
|
92
|
+
year_tens = (last_two_digits // 10) * 10
|
|
93
|
+
year_ones = last_two_digits % 10
|
|
94
|
+
|
|
95
|
+
if year_ones == 0:
|
|
96
|
+
return f"{millennium_text} {d[year_tens][0]}"
|
|
97
|
+
else:
|
|
98
|
+
return f"{millennium_text} {d[year_tens][0]} {d[year_ones][0]}"
|
|
99
|
+
|
|
100
|
+
# Regular number handling
|
|
101
|
+
if num in d:
|
|
102
|
+
return d[num][1 if is_spoken else 0]
|
|
103
|
+
|
|
104
|
+
# Add check for special_vis numbers (20-29)
|
|
105
|
+
if num in special_vis:
|
|
106
|
+
return special_vis[num]
|
|
107
|
+
|
|
108
|
+
if num < 100:
|
|
109
|
+
if is_spoken:
|
|
110
|
+
thousands = True
|
|
111
|
+
|
|
112
|
+
base = (num // 10) * 10
|
|
113
|
+
remainder = num % 10
|
|
114
|
+
|
|
115
|
+
if remainder == 0:
|
|
116
|
+
return d[base][1 if is_spoken else 0]
|
|
117
|
+
|
|
118
|
+
return f"{d[base][1 if is_spoken else 0]} {d[remainder][0 if thousands else 1]}"
|
|
119
|
+
|
|
120
|
+
if num < k:
|
|
121
|
+
hundreds = num // 100
|
|
122
|
+
remainder = num % 100
|
|
123
|
+
|
|
124
|
+
if hundreds == 2:
|
|
125
|
+
hundreds_text = f"{d[hundreds][0]}ސައްތަ"
|
|
126
|
+
else:
|
|
127
|
+
hundreds_text = f"{d[hundreds][0]}ސަތޭކަ"
|
|
128
|
+
|
|
129
|
+
if remainder == 0:
|
|
130
|
+
return hundreds_text
|
|
131
|
+
return f"{hundreds_text} {int_to_dv(remainder, False, is_spoken)}"
|
|
132
|
+
|
|
133
|
+
if num < m:
|
|
134
|
+
thousands = num // k
|
|
135
|
+
remainder = num % k
|
|
136
|
+
# Get the number text and convert to haas form if needed
|
|
137
|
+
thousands_text = int_to_dv(thousands, True)
|
|
138
|
+
for spoken_form, haas_form in haas_map.items():
|
|
139
|
+
if thousands_text.endswith(spoken_form):
|
|
140
|
+
thousands_text = thousands_text[:-len(spoken_form)] + haas_form
|
|
141
|
+
break
|
|
142
|
+
|
|
143
|
+
thousands_text = f"{thousands_text}ހާސް"
|
|
144
|
+
if remainder == 0:
|
|
145
|
+
return thousands_text
|
|
146
|
+
return f"{thousands_text} {int_to_dv(remainder, False, is_spoken)}"
|
|
147
|
+
|
|
148
|
+
if num < b:
|
|
149
|
+
millions = num // m
|
|
150
|
+
remainder = num % m
|
|
151
|
+
millions_text = f"{int_to_dv(millions, True)}މިލިއަން"
|
|
152
|
+
if remainder == 0:
|
|
153
|
+
return millions_text
|
|
154
|
+
return f"{millions_text} {int_to_dv(remainder, False, is_spoken)}"
|
|
155
|
+
|
|
156
|
+
if num < t:
|
|
157
|
+
billions = num // b
|
|
158
|
+
remainder = num % b
|
|
159
|
+
billions_text = f"{int_to_dv(billions, True)}ބިލިއަން"
|
|
160
|
+
if remainder == 0:
|
|
161
|
+
return billions_text
|
|
162
|
+
return f"{billions_text} {int_to_dv(remainder, False, is_spoken)}"
|
|
163
|
+
|
|
164
|
+
trillions = num // t
|
|
165
|
+
remainder = num % t
|
|
166
|
+
trillions_text = f"{int_to_dv(trillions, True)}ޓްރިލިއަން"
|
|
167
|
+
if remainder == 0:
|
|
168
|
+
return trillions_text
|
|
169
|
+
return f"{trillions_text} {int_to_dv(remainder, False, is_spoken)}"
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from dv_normalize.dv_num import int_to_dv
|
|
3
|
+
|
|
4
|
+
def replace_digits_with_dv(text: str) -> str:
|
|
5
|
+
"""
|
|
6
|
+
Convert all numbers in text to Dhivehi, handling different formats:
|
|
7
|
+
- Regular numbers
|
|
8
|
+
- Years (when followed by ވަނަ)
|
|
9
|
+
- Decimal numbers
|
|
10
|
+
"""
|
|
11
|
+
def convert_match(match):
|
|
12
|
+
full_num = match.group(0)
|
|
13
|
+
|
|
14
|
+
# Handle decimal numbers
|
|
15
|
+
if '.' in full_num:
|
|
16
|
+
whole, decimal = full_num.split('.')
|
|
17
|
+
whole_dv = int_to_dv(int(whole), is_spoken=True)
|
|
18
|
+
decimal_dv = ' '.join(int_to_dv(int(d), is_spoken=True) for d in decimal)
|
|
19
|
+
return f"{whole_dv} ޕޮއިންޓު {decimal_dv}"
|
|
20
|
+
|
|
21
|
+
num = int(full_num)
|
|
22
|
+
|
|
23
|
+
# Check if next word is ވަނަ (indicates year)
|
|
24
|
+
text_after = text[match.end():].strip()
|
|
25
|
+
if text_after.startswith('ވަނަ'):
|
|
26
|
+
return int_to_dv(num, is_year=True)
|
|
27
|
+
|
|
28
|
+
# Regular number conversion
|
|
29
|
+
return int_to_dv(num, is_spoken=True)
|
|
30
|
+
|
|
31
|
+
# Remove commas from numbers first
|
|
32
|
+
text = text.replace(',', '')
|
|
33
|
+
|
|
34
|
+
# Convert all numbers using the pattern
|
|
35
|
+
pattern = r'\d+(?:\.\d+)?'
|
|
36
|
+
text = re.sub(pattern, convert_match, text)
|
|
37
|
+
|
|
38
|
+
return text
|
|
39
|
+
|
|
40
|
+
def normalize_sentence_end(text: str) -> str:
|
|
41
|
+
"""
|
|
42
|
+
Normalize Dhivehi sentence endings using common patterns for spoken form
|
|
43
|
+
"""
|
|
44
|
+
patterns = [
|
|
45
|
+
# Noun endings with އެކެވެ
|
|
46
|
+
(r'([ަ-ް]*?)އެކެވެ', r'\1އެއް'),
|
|
47
|
+
(r'([ަ-ް]*?)ކެކެވެ', r'\1ކެއް'),
|
|
48
|
+
(r'([ަ-ް]*?)ތެކެވެ', r'\1ތެއް'),
|
|
49
|
+
(r'([ަ-ް]*?)މެކެވެ', r'\1މެއް'),
|
|
50
|
+
(r'([ަ-ް]*?)ހެކެވެ', r'\1ހެއް'),
|
|
51
|
+
(r'([ަ-ް]*?)ރެކެވެ', r'\1ރެއް'),
|
|
52
|
+
(r'([ަ-ް]*?)ޅެކެވެ', r'\1ޅެއް'),
|
|
53
|
+
|
|
54
|
+
# Endings that convert to ށް
|
|
55
|
+
(r'ށެވެ', 'ށް'),
|
|
56
|
+
(r'އަށެވެ', 'އަށް'),
|
|
57
|
+
(r'ޔަށެވެ', 'ޔަށް'),
|
|
58
|
+
(r'ކަށެވެ', 'ކަށް'),
|
|
59
|
+
(r'ތަށެވެ', 'ތަށް'),
|
|
60
|
+
(r'ޗަށެވެ', 'ޗަށް'),
|
|
61
|
+
(r'ނަށެވެ', 'ނަށް'),
|
|
62
|
+
(r'ރަށެވެ', 'ރަށް'),
|
|
63
|
+
(r'ދަށެވެ', 'ދަށް'),
|
|
64
|
+
|
|
65
|
+
# Common verb endings
|
|
66
|
+
(r'ވެއެވެ', 'ވޭ'),
|
|
67
|
+
(r'ނެއެވެ', 'ނެ'),
|
|
68
|
+
(r'ވިއެވެ', 'ވި'),
|
|
69
|
+
(r'ދެއެވެ', 'ދޭ'),
|
|
70
|
+
(r'ޖެއެވެ', 'ޖެ'),
|
|
71
|
+
(r'ލެއެވެ', 'ލެ'),
|
|
72
|
+
(r'ހުރެއެވެ', 'ހުރޭ'),
|
|
73
|
+
(r'ބެއެވެ', 'ބޭ'),
|
|
74
|
+
(r'ރެއެވެ', 'ރޭ'),
|
|
75
|
+
|
|
76
|
+
# Common noun endings
|
|
77
|
+
(r'ތަކެވެ', 'ތައް'),
|
|
78
|
+
(r'ގައެވެ', 'ގައި'),
|
|
79
|
+
(r'އަހެވެ', 'ވަސް'),
|
|
80
|
+
(r'ބަހެވެ', 'ބަސް'),
|
|
81
|
+
|
|
82
|
+
# Endings that convert to ން
|
|
83
|
+
(r'އިންނެވެ', 'އިން'),
|
|
84
|
+
(r'ންނެވެ', 'ން'),
|
|
85
|
+
(r'ދުނެވެ', 'ދުން'),
|
|
86
|
+
(r'ދުމެވެ', 'ދުން'),
|
|
87
|
+
(r'ރުމެވެ', 'ރުން'),
|
|
88
|
+
(r'މުމެވެ', 'މުން'),
|
|
89
|
+
(r'ޅެމެވެ', 'ޅެން'),
|
|
90
|
+
(r'ޔުމެވެ', 'ޔުން'),
|
|
91
|
+
|
|
92
|
+
# Special cases
|
|
93
|
+
(r'ނޫނެވެ', 'ނޫން'),
|
|
94
|
+
(r'ހުއްޓެވެ', 'ހުރި'),
|
|
95
|
+
(r'ލެވެ', 'ލު'),
|
|
96
|
+
(r'ދެވެ', 'ދު'),
|
|
97
|
+
(r'ރެވެ', 'ރު'),
|
|
98
|
+
(r'ޅެވެ', 'ޅު'),
|
|
99
|
+
|
|
100
|
+
# Remove standalone އެވެ (should be last)
|
|
101
|
+
(r'\s*އެވެ', ''),
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
# Apply patterns
|
|
105
|
+
for pattern, replacement in patterns:
|
|
106
|
+
text = re.sub(pattern, replacement, text)
|
|
107
|
+
|
|
108
|
+
return text.strip()
|
|
109
|
+
|
|
110
|
+
def spoken_dv(text: str) -> str:
|
|
111
|
+
"""
|
|
112
|
+
Normalize Dhivehi text by:
|
|
113
|
+
1. Converting numbers to spoken form (including years and decimals)
|
|
114
|
+
2. Normalizing sentence endings
|
|
115
|
+
3. Removing special characters
|
|
116
|
+
4. Cleaning up whitespace
|
|
117
|
+
"""
|
|
118
|
+
if not text or not isinstance(text, str):
|
|
119
|
+
return ""
|
|
120
|
+
|
|
121
|
+
# Pre-process
|
|
122
|
+
text = text.strip()
|
|
123
|
+
|
|
124
|
+
# Apply normalizations
|
|
125
|
+
text = normalize_sentence_end(text)
|
|
126
|
+
text = replace_digits_with_dv(text)
|
|
127
|
+
|
|
128
|
+
# Post-process to fix spacing
|
|
129
|
+
text = re.sub(r'(?<=[ހ-ޥ])\s+(?=[ަ-ް])', '', text) # Fix diacritic spacing
|
|
130
|
+
text = re.sub(r'\s+([.،؟!])', r'\1', text) # Fix punctuation spacing
|
|
131
|
+
text = re.sub(r'\s+', ' ', text) # Normalize spaces
|
|
132
|
+
|
|
133
|
+
return text.strip()
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: dv-normalizer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python library for normalizing Dhivehi text and converting numbers to Dhivehi text format, supporting written, spoken and year forms
|
|
5
|
+
Author: Alakxender
|
|
6
|
+
Author-email: alakxender@gmail.com
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENCE
|
|
10
|
+
|
|
11
|
+
# dv-normalize
|
|
12
|
+
|
|
13
|
+
A Python library for normalizing Dhivehi text by converting numbers to Dhivehi and standardizing sentence endings.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- Converts numbers to Dhivehi text (both written and spoken forms)
|
|
18
|
+
- Handles years (when followed by ވަނަ)
|
|
19
|
+
- Handles decimal numbers
|
|
20
|
+
- Normalizes formal sentence endings to colloquial form
|
|
21
|
+
- Preserves proper spacing and punctuation
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install dv-normalize
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
There are two main functions in this library:
|
|
32
|
+
|
|
33
|
+
1. `int_to_dv` - This function converts numbers to Dhivehi text in written form.
|
|
34
|
+
2. `spoken_dv` - This function converts dhivehi text to spoken form.
|
|
35
|
+
|
|
36
|
+
### Written form
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
|
|
40
|
+
## test case for int_to_dv
|
|
41
|
+
|
|
42
|
+
from dv_normalize.dv_num import int_to_dv
|
|
43
|
+
|
|
44
|
+
def main():
|
|
45
|
+
while True:
|
|
46
|
+
try:
|
|
47
|
+
num = input("Enter a number (0 to trillion) or 'q' to exit: ")
|
|
48
|
+
if num.lower() == 'q':
|
|
49
|
+
break
|
|
50
|
+
|
|
51
|
+
num = int(num)
|
|
52
|
+
if num < 0:
|
|
53
|
+
print("Please enter a non-negative number")
|
|
54
|
+
continue
|
|
55
|
+
|
|
56
|
+
print(f"{num:,} in Dhivehi:")
|
|
57
|
+
written = int_to_dv(num, is_spoken=False)
|
|
58
|
+
spoken = int_to_dv(num, is_spoken=True)
|
|
59
|
+
year = "Not a valid year format" if num < 1000 or num > 9999 else int_to_dv(num, is_year=True)
|
|
60
|
+
|
|
61
|
+
print(f"Written form: {written}")
|
|
62
|
+
print(f"Spoken form: {spoken}")
|
|
63
|
+
print(f"Year form: {year}")
|
|
64
|
+
|
|
65
|
+
except ValueError:
|
|
66
|
+
print("Please enter a valid number")
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
main()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Spoken form
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from dv_normalize.dv_sentence import spoken_dv
|
|
76
|
+
|
|
77
|
+
# Test cases
|
|
78
|
+
test_cases = [
|
|
79
|
+
"މިއަދު ވަރަށް ފިނިވެއެވެ.", # Verb ending
|
|
80
|
+
"މިއީ ރީތި ފޮތެކެވެ.", # Noun ending
|
|
81
|
+
"އޭނާ ދަނީ ސްކޫލަށެވެ.", # Direction ending
|
|
82
|
+
"1955 މީހުން ތިބެއެވެ.", # Number with ending
|
|
83
|
+
"2024 ވަނަ އަހަރު", # Year
|
|
84
|
+
"12.5 ރުފިޔާ", # Decimal
|
|
85
|
+
"1000 މީހުން", # Regular number
|
|
86
|
+
"މިއީ ރީތި ފޮތެކެވެ.", # Sentence ending
|
|
87
|
+
"އޭނާ ގެއަށެވެ.", # Sentence ending
|
|
88
|
+
"ހާއްސަ އެއްބަސްވުމުގެ ދަށުން އިންޑިއާއިން ރާއްޖެއަށް ވިއްކާ ހަކުރު އޮޅުވާލައިގެން ލަންކާއަށް!", # test sentence
|
|
89
|
+
"އެ އިދާރާއިން ބަލަމުން އަންނަނީ މިދިޔަ މަހުގެ 25 ގައި އެގައުމުން ބޭރު ކުރި 64 ހާސް ޓަނުގެ ހަކުރުގެ ޝިޕްމެންޓެއްގެ މައްސަލަ އެވެ. އެ ޝިޕްމެންޓް އެގައުމުން ބޭރުކުރީ ރާއްޖެ އާއި އިންޑިއާ އާ ދެމެދު ވެފައިވާ ވިޔަފާރީގެ ހާއްސަ އެއްބަސްވުމުގެ ދަށުން ކަނޑައަޅާފައިވާ އަގުތަކުގައި ނަމަވެސް، އެއިން ބައެއް ލަންކާއަށް އެތެރެކުރިން ފަޅާއަރާފައިވާ ކަމަށް އިންޑިއާގެ ބައެއް ނޫސްތަކުގައި ރިފޯޓުކޮށްފައިވެ އެވެ." # test long sentence
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
for test in test_cases:
|
|
93
|
+
print(f"Original: {test}")
|
|
94
|
+
print(f"Normalized: {spoken_dv(test)}\n")
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENCE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
dv_normalize/__init__.py
|
|
6
|
+
dv_normalize/dv_num.py
|
|
7
|
+
dv_normalize/dv_sentence.py
|
|
8
|
+
dv_normalizer.egg-info/PKG-INFO
|
|
9
|
+
dv_normalizer.egg-info/SOURCES.txt
|
|
10
|
+
dv_normalizer.egg-info/dependency_links.txt
|
|
11
|
+
dv_normalizer.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dv_normalize
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r") as f:
|
|
4
|
+
long_description = f.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="dv-normalizer",
|
|
8
|
+
version="0.1.0",
|
|
9
|
+
description="A Python library for normalizing Dhivehi text and converting numbers to Dhivehi text format, supporting written, spoken and year forms",
|
|
10
|
+
author="Alakxender",
|
|
11
|
+
author_email="alakxender@gmail.com",
|
|
12
|
+
packages=find_packages(),
|
|
13
|
+
python_requires=">=3.8",
|
|
14
|
+
include_package_data=True,
|
|
15
|
+
package_data={
|
|
16
|
+
"dv_normalizer": ["*.yaml", "*.json", "configs/*"],
|
|
17
|
+
},
|
|
18
|
+
long_description=long_description,
|
|
19
|
+
long_description_content_type="text/markdown",
|
|
20
|
+
)
|