File size: 10,685 Bytes
ac901c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# coding: utf8
"""

Character Normalization functions

provides functionality to put proper spaces before and after numeric digits, urdu digits

and punctuations.

"""
from typing import Dict, List
import logging

from .regexes import _DIACRITICS_RE
from .regexes import _SPACE_AFTER_PUNCTUATIONS_RE, _REMOVE_SPACE_BEFORE_PUNCTUATIONS_RE

logger = logging.getLogger(__name__)

# Contains wrong Urdu characters mapping to correct characters
_CORRECT_URDU_CHARACTERS_MAPPING: Dict[str, List[str]] = {
    "آ": ["ﺁ", "ﺂ"],
    "أ": ["ﺃ"],
    "ا": [
        "ﺍ",
        "ﺎ",
    ],
    "ب": ["ﺏ", "ﺐ", "ﺑ", "ﺒ"],
    "پ": [
        "ﭖ",
        "ﭘ",
        "ﭙ",
    ],
    "ت": ["ﺕ", "ﺖ", "ﺗ", "ﺘ"],
    "ٹ": ["ﭦ", "ﭧ", "ﭨ", "ﭩ"],
    "ث": ["ﺛ", "ﺜ", "ﺚ"],
    "ج": ["ﺝ", "ﺞ", "ﺟ", "ﺠ"],
    "ح": ["ﺡ", "ﺣ", "ﺤ", "ﺢ"],
    "خ": ["ﺧ", "ﺨ", "ﺦ"],
    "د": ["ﺩ", "ﺪ"],
    "ذ": ["ﺬ", "ﺫ"],
    "ر": ["ﺭ", "ﺮ"],
    "ز": [
        "ﺯ",
        "ﺰ",
    ],
    "س": [
        "ﺱ",
        "ﺲ",
        "ﺳ",
        "ﺴ",
    ],
    "ش": ["ﺵ", "ﺶ", "ﺷ", "ﺸ"],
    "ص": [
        "ﺹ",
        "ﺺ",
        "ﺻ",
        "ﺼ",
    ],
    "ض": ["ﺽ", "ﺾ", "ﺿ", "ﻀ"],
    "ط": ["ﻃ", "ﻄ"],
    "ظ": ["ﻅ", "ﻇ", "ﻈ"],
    "ع": [
        "ﻉ",
        "ﻊ",
        "ﻋ",
        "ﻌ",
    ],
    "غ": [
        "ﻍ",
        "ﻏ",
        "ﻐ",
    ],
    "ف": [
        "ﻑ",
        "ﻒ",
        "ﻓ",
        "ﻔ",
    ],
    "ق": [
        "ﻕ",
        "ﻖ",
        "ﻗ",
        "ﻘ",
    ],
    "ل": [
        "ﻝ",
        "ﻞ",
        "ﻟ",
        "ﻠ",
    ],
    "م": [
        "ﻡ",
        "ﻢ",
        "ﻣ",
        "ﻤ",
    ],
    "ن": [
        "ﻥ",
        "ﻦ",
        "ﻧ",
        "ﻨ",
    ],
    "چ": ["ﭺ", "ﭻ", "ﭼ", "ﭽ"],
    "ڈ": ["ﮈ", "ﮉ"],
    "ڑ": ["ﮍ", "ﮌ"],
    "ژ": [
        "ﮋ",
    ],
    "ک": ["ﮎ", "ﮏ", "ﮐ", "ﮑ", "ﻛ", "ك"],
    "گ": ["ﮒ", "ﮓ", "ﮔ", "ﮕ"],
    "ں": ["ﮞ", "ﮟ"],
    "و": [
        "ﻮ",
        "ﻭ",
        "ﻮ",
    ],
    "ؤ": ["ﺅ"],
    "ھ": ["ﮪ", "ﮬ", "ﮭ", "ﻬ", "ﻫ", "ﮫ"],
    "ہ": [
        "ﻩ",
        "ﮦ",
        "ﻪ",
        "ﮧ",
        "ﮩ",
        "ﮨ",
        "ه",
    ],
    "ۂ": [],
    "ۃ": ["ة"],
    "ء": ["ﺀ"],
    "ی": ["ﯼ", "ى", "ﯽ", "ﻰ", "ﻱ", "ﻲ", "ﯾ", "ﯿ", "ي"],
    "ئ": [
        "ﺋ",
        "ﺌ",
    ],
    "ے": [
        "ﮮ",
        "ﮯ",
        "ﻳ",
        "ﻴ",
    ],
    "ۓ": [],
    "۰": ["٠"],
    "۱": ["١"],
    "۲": ["٢"],
    "۳": ["٣"],
    "۴": ["٤"],
    "۵": ["٥"],
    "۶": ["٦"],
    "۷": ["٧"],
    "۸": ["٨"],
    "۹": ["٩"],
    "۔": [],
    "؟": [],
    "٫": [],
    "،": [],
    "لا": ["ﻻ", "ﻼ"],
    "": ["ـ"],
}

_TRANSLATOR = {}
for key, value in _CORRECT_URDU_CHARACTERS_MAPPING.items():
    _TRANSLATOR.update(dict.fromkeys(map(ord, value), key))


def normalize_characters(text: str) -> str:
    """

    The most important module in the UrduHack is the :py:mod:`~urduhack.normalization.character` module,

    defined in the module with the same name. You can use this module separately to normalize

    a piece of text to a proper specified Urdu range (0600-06FF). To get an understanding of how this module works, one

    needs to understand unicode. Every character has a unicode. You can search for any character unicode from any

    language you will find it. No two characters can have the same unicode. This module works with reference to the

    unicodes. Now as urdu language has its roots in Arabic, Parsian and Turkish. So we have to deal with all those

    characters and convert them to a normal urdu character. To get a bit more of what the above explanation means is.::



    >>> all_fes = ['ﻑ', 'ﻒ', 'ﻓ', 'ﻔ', ]

    >>> urdu_fe = 'ف'



    All the characters in all_fes are same but they come from different languages and they all have different unicodes.

    Now as computers deal with numbers, same character appearing in more than one place in a different language will

    have a different unicode and that will create confusion which will create problems in understanding the context of

    the data. :py:mod:`~character` module will eliminate this problem by replacing all the characters in all_fes by

    urdu_fe.



    This provides the functionality to replace wrong arabic characters with correct urdu characters and fixed the

    combine|join characters issue.



    Replace ``urdu`` text characters with correct ``unicode`` characters.



    Args:

        text : ``Urdu`` text

    Returns:

        str: Returns a ``str`` object containing normalized text.

    Examples:

        >>> from urduhack.normalization import normalize_characters

        >>> # Text containing characters from Arabic Unicode block

        >>> _text = "مجھ کو جو توڑا ﮔیا تھا"

        >>> normalized_text = normalize_characters(_text)

        >>> # Normalized text - Arabic characters are now replaced with Urdu characters

        >>> normalized_text

        مجھ کو جو توڑا گیا تھا

    """
    return text.translate(_TRANSLATOR)


COMBINE_URDU_CHARACTERS: Dict[str, str] = {
    "آ": "آ",
    "أ": "أ",
    "ۓ": "ۓ",
}


# Issue to be resolved: Words like کیجئے and کیجیے appear in the same context but they have different unicodes.
# We cannot merge them neither can we have them separately. Because if we decompose ئ,
# we get unicode that are not available in our unicode list.


def normalize_combine_characters(text: str) -> str:
    """

    To normalize combine characters with single character unicode text, use the

    :py:func:`~urduhack.normalization.character.normalize_combine_characters` function in the

    :py:mod:`~urduhack.normalization.character` module.



    Replace combine|join ``urdu`` characters with single unicode character



    Args:

        text : ``Urdu`` text

    Returns:

        str: Returns a ``str`` object containing normalized text.

    Examples:

        >>> from urduhack.normalization import normalize_combine_characters

        >>> # In the following string, Alif ('ا') and Hamza ('ٔ ') are separate characters

        >>> _text = "جرأت"

        >>> normalized_text = normalize_combine_characters(_text)

        >>> # Now Alif and Hamza are replaced by a Single Urdu Unicode Character!

        >>> normalized_text

        جرأت

    """
    for _key, _value in COMBINE_URDU_CHARACTERS.items():
        text = text.replace(_key, _value)
    return text


def punctuations_space(text: str) -> str:
    """

    Add spaces after punctuations used in ``urdu`` writing



    Args:

        text : ``Urdu`` text

    Returns:

        str: Returns a ``str`` object containing normalized text.

    Examples:

        >>> from urduhack.normalization.character import punctuations_space

        >>> _text = "ہوتا ہے   ۔  ٹائپ"

        >>> normalized_text = punctuations_space(_text)

        >>> normalized_text

        ہوتا ہے۔ ٹائپ

    """
    text = _SPACE_AFTER_PUNCTUATIONS_RE.sub(" ", text)
    text = _REMOVE_SPACE_BEFORE_PUNCTUATIONS_RE.sub(r"\1", text)
    return text


def remove_diacritics(text: str) -> str:
    """

    Remove ``urdu`` diacritics from text. It is an important step in pre-processing of the Urdu data.

    This function returns a String object which contains the original text minus Urdu diacritics.



    Args:

        text : ``Urdu`` text

    Returns:

        str: Returns a ``str`` object containing normalized text.

    Examples:

        >>> from urduhack.normalization import remove_diacritics

        >>> _text = "شیرِ پنجاب"

        >>> normalized_text = remove_diacritics(_text)

        >>> normalized_text

        شیر پنجاب

    """
    return _DIACRITICS_RE.sub("", text)


ENG_URDU_DIGITS_MAP: Dict = {
    "0": ["۰"],
    "1": ["۱"],
    "2": ["۲"],
    "3": ["۳"],
    "4": ["۴"],
    "5": ["۵"],
    "6": ["۶"],
    "7": ["۷"],
    "8": ["۸"],
    "9": ["۹"],
}

_ENG_DIGITS_TRANSLATOR = {}
for key, value in ENG_URDU_DIGITS_MAP.items():
    _ENG_DIGITS_TRANSLATOR.update(dict.fromkeys(map(ord, value), key))

URDU_ENG_DIGITS_MAP: Dict = {
    "۰": ["0"],
    "۱": ["1"],
    "۲": ["2"],
    "۳": ["3"],
    "۴": ["4"],
    "۵": ["5"],
    "۶": ["6"],
    "۷": ["7"],
    "۸": ["8"],
    "۹": ["9"],
}

_URDU_DIGITS_TRANSLATOR = {}
for key, value in URDU_ENG_DIGITS_MAP.items():
    _URDU_DIGITS_TRANSLATOR.update(dict.fromkeys(map(ord, value), key))


def replace_digits(text: str, with_english: bool = True) -> str:
    """

    Replace urdu digits with English digits and vice versa



    Args:

        text : Urdu text string

        with_english (bool): Boolean to convert digits from one language to other

    Returns:

        Text string with replaced digits

    """
    if with_english:
        return text.translate(_ENG_DIGITS_TRANSLATOR)
    return text.translate(_URDU_DIGITS_TRANSLATOR)


def normalize(text: str) -> str:
    """

    To normalize some text, all you need to do pass ``Urdu`` text. It will return a ``str``

    with normalized characters both single and combined, proper spaces after digits and punctuations

    and diacritics removed.



    Args:

        text : ``Urdu`` text

    Returns:

        str: Normalized ``Urdu`` text

    Raises:

        TypeError: If text param is not not str Type.

    Examples:

        >>> from urduhack import normalize

        >>> _text = "اَباُوگل پاکستان ﻤﯿﮟ 20 سال ﺳﮯ ، وسائل کی کوئی کمی نہیں ﮨﮯ۔"

        >>> normalized_text = normalize(_text)

        >>> # The text now contains proper spaces after digits and punctuations,

        >>> # normalized characters and no diacritics!

        >>> normalized_text

        اباوگل پاکستان ﻤﯿﮟ 20 سال ﺳﮯ ، وسائل کی کوئی کمی نہیں ﮨﮯ۔

    """
    if not isinstance(text, str):
        raise TypeError("Text must be str type.")

    logger.info("Normalizing the text.")

    text = remove_diacritics(text)
    text = normalize_characters(text)
    text = normalize_combine_characters(text)
    return text