python-negar 1.2.9__tar.gz → 1.2.12__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.
- {python-negar-1.2.9 → python_negar-1.2.12}/Changelog.txt +28 -22
- {python-negar-1.2.9 → python_negar-1.2.12}/MANIFEST.in +1 -1
- {python-negar-1.2.9 → python_negar-1.2.12}/PKG-INFO +3 -10
- {python-negar-1.2.9 → python_negar-1.2.12}/README.md +1 -1
- {python-negar-1.2.9 → python_negar-1.2.12}/negar/constants.py +3 -3
- {python-negar-1.2.9 → python_negar-1.2.12}/negar/virastar.py +65 -43
- {python-negar-1.2.9 → python_negar-1.2.12}/python_negar.egg-info/PKG-INFO +3 -10
- {python-negar-1.2.9 → python_negar-1.2.12}/python_negar.egg-info/SOURCES.txt +3 -3
- {python-negar-1.2.9 → python_negar-1.2.12}/python_negar.egg-info/entry_points.txt +0 -1
- {python-negar-1.2.9 → python_negar-1.2.12}/setup.py +1 -6
- python_negar-1.2.12/tests/test_unittest.py +126 -0
- python-negar-1.2.9/negar/data/__init__.py +0 -0
- {python-negar-1.2.9 → python_negar-1.2.12}/AUTHORS +0 -0
- {python-negar-1.2.9 → python_negar-1.2.12}/LICENSE +0 -0
- {python-negar-1.2.9 → python_negar-1.2.12}/negar/__init__.py +0 -0
- /python-negar-1.2.9/negar/data/untouchable.dat → /python_negar-1.2.12/negar/data/immutable.words +0 -0
- {python-negar-1.2.9 → python_negar-1.2.12}/negar/gui.py +0 -0
- {python-negar-1.2.9 → python_negar-1.2.12}/python_negar.egg-info/dependency_links.txt +0 -0
- {python-negar-1.2.9 → python_negar-1.2.12}/python_negar.egg-info/requires.txt +0 -0
- {python-negar-1.2.9 → python_negar-1.2.12}/python_negar.egg-info/top_level.txt +0 -0
- {python-negar-1.2.9 → python_negar-1.2.12}/setup.cfg +0 -0
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
1.2.12 - 2024-12-23
|
|
2
|
+
-- Fix critical issue with naming `immutable.words`
|
|
3
|
+
|
|
4
|
+
1.2.11 - 2024-12-23
|
|
5
|
+
-- Typo Fix
|
|
6
|
+
-- Renamed `untouchable.dat` to `immutable.words`
|
|
7
|
+
|
|
1
8
|
1.2.9 - 2024-05-07
|
|
2
|
-
-- Fix subtle issue with
|
|
3
|
-
-- new test for
|
|
9
|
+
-- Fix subtle issue with immutable words which stick to non-literal symbols like Parentheses
|
|
10
|
+
-- new test for immutable words
|
|
4
11
|
|
|
5
12
|
1.2.8 - 2023-09-21
|
|
6
13
|
-- Fix subtle issue with triple dots at the end of sentence followed by another [?!.]
|
|
@@ -9,13 +16,13 @@
|
|
|
9
16
|
-- Remove dot from saving directory under Windows OS.
|
|
10
17
|
|
|
11
18
|
1.2.6 - 2023-08-07
|
|
12
|
-
-- Better location for saving user defined
|
|
19
|
+
-- Better location for saving user defined immutable data under Windows OS.
|
|
13
20
|
|
|
14
21
|
1.2.5 - 2023-07-14
|
|
15
22
|
-- Fix issues with texts that include backslashes as part of their context, such as LaTeX source code.
|
|
16
23
|
|
|
17
24
|
1.2.4 - 2023-06-15
|
|
18
|
-
-- Fix the issue with multiple ! and ? and extra space after
|
|
25
|
+
-- Fix the issue with multiple ! and ? and extra space after parentheses at the end of line
|
|
19
26
|
|
|
20
27
|
1.2.2 - 2023-06-13
|
|
21
28
|
-- Fix the issue with the triple dots that was caused by the previous update
|
|
@@ -28,7 +35,7 @@
|
|
|
28
35
|
|
|
29
36
|
1.1.17 - 2022-12-21
|
|
30
37
|
-- Fix the issue with می and نمی when they come as nouns, not prefixes.
|
|
31
|
-
-- Several new
|
|
38
|
+
-- Several new immutable words: تنهای/تنهایی/تکوتنهایی
|
|
32
39
|
|
|
33
40
|
1.1.16 - 2022-09-11
|
|
34
41
|
-- Fix issues with the following بهمان ,مهاجمان
|
|
@@ -55,7 +62,7 @@
|
|
|
55
62
|
-- Update in compliance with `negar-gui` ver 0.2
|
|
56
63
|
|
|
57
64
|
1.1.8 - 2012-05-03
|
|
58
|
-
-- minor issue with
|
|
65
|
+
-- minor issue with immutable words
|
|
59
66
|
-- remove `disutils` as it's deprecated now
|
|
60
67
|
|
|
61
68
|
1.1.7 - 2012-04-21
|
|
@@ -82,7 +89,7 @@
|
|
|
82
89
|
|
|
83
90
|
1.1.1 - 2022-04-08
|
|
84
91
|
-- Fixed an issue with `^mi*haye$` with using regex module
|
|
85
|
-
--
|
|
92
|
+
-- Support for new suffix شناس/شناسی
|
|
86
93
|
|
|
87
94
|
1.1 - 2022-04-07
|
|
88
95
|
-- Downgraded to PyQt5 for better support in Windows.
|
|
@@ -123,7 +130,7 @@
|
|
|
123
130
|
|
|
124
131
|
0.9.6 - 2022-04-02
|
|
125
132
|
-- Fixed issue #21, suffix اش
|
|
126
|
-
--
|
|
133
|
+
-- Immutable words updated
|
|
127
134
|
|
|
128
135
|
0.9.5 - 2022-04-01
|
|
129
136
|
-- New options for trimming leading/trailing whitespaces
|
|
@@ -145,11 +152,11 @@
|
|
|
145
152
|
-- Revision of functions' names and their docstrings and comments to fix issue #14
|
|
146
153
|
|
|
147
154
|
0.8.9 - 2022-03-29
|
|
148
|
-
--
|
|
155
|
+
-- Support of import button via QFileDialog
|
|
149
156
|
|
|
150
157
|
0.8.8 - 2022-03-29
|
|
151
158
|
-- constants.py would encompass some constants variables like __version__
|
|
152
|
-
--
|
|
159
|
+
-- Immutable words update
|
|
153
160
|
|
|
154
161
|
0.8.7 - 2022-03-29
|
|
155
162
|
-- Fixed issue #4, users just add their own words to their private file-system
|
|
@@ -168,16 +175,16 @@
|
|
|
168
175
|
|
|
169
176
|
0.8.2 - 2022-03-27
|
|
170
177
|
-- copy button redesign
|
|
171
|
-
--
|
|
178
|
+
-- Immutable words revision
|
|
172
179
|
|
|
173
180
|
0.8.1 - 2022-03-27
|
|
174
181
|
-- Auto Stretch of headers in QTableView
|
|
175
182
|
-- No header name for QTableView
|
|
176
183
|
|
|
177
184
|
0.8.0 - 2022-03-26
|
|
178
|
-
-- Extra Class for
|
|
179
|
-
-- Shows
|
|
180
|
-
--
|
|
185
|
+
-- Extra Class for immutable words
|
|
186
|
+
-- Shows immutable words in config tab via QTableView
|
|
187
|
+
-- Immutable words update
|
|
181
188
|
-- Right alignment for data in QTableView
|
|
182
189
|
|
|
183
190
|
0.7.4 - 2022-03-25
|
|
@@ -185,7 +192,7 @@
|
|
|
185
192
|
-- Fixed issue with relative import (https://stackoverflow.com/questions/16981921)
|
|
186
193
|
|
|
187
194
|
0.7.3 - 2022-03-25
|
|
188
|
-
--
|
|
195
|
+
-- Immutable words update
|
|
189
196
|
-- Fixed issue with import
|
|
190
197
|
|
|
191
198
|
0.7.2 - 2022-03-24
|
|
@@ -204,32 +211,32 @@
|
|
|
204
211
|
0.6.8 - 2022-03-21
|
|
205
212
|
-- os replaced by Pathlib
|
|
206
213
|
-- Fixed some hot-keys in `Config` tab
|
|
207
|
-
-- fixed the issue with 'می' at the
|
|
214
|
+
-- fixed the issue with 'می' at the beginning of the line
|
|
208
215
|
|
|
209
216
|
0.6.7 - 2022-03-20
|
|
210
217
|
-- auto focus on input field
|
|
211
218
|
|
|
212
219
|
0.6.6 - 2022-03-19
|
|
213
220
|
-- Fixed issue with words that contain 'ها' in the middle or at the end, like 'مهاباد' and 'دانشکده ها'
|
|
214
|
-
--
|
|
221
|
+
-- Immutable words list update as well as redundancy removed
|
|
215
222
|
-- Removing unwanted extra zwmjs
|
|
216
223
|
-- Negar logo for better desktop switching
|
|
217
224
|
|
|
218
225
|
0.6.5 - 2022-03-18
|
|
219
226
|
-- Font Size Slider relocate to the bottom
|
|
220
227
|
-- Fixed issue with words that contain 'می' in the middle like 'سهمیه'
|
|
221
|
-
-- Tremendous addition of words start with 'می' into
|
|
228
|
+
-- Tremendous addition of words start with 'می' into immutable words
|
|
222
229
|
|
|
223
230
|
0.6.4 - 2022-03-18
|
|
224
231
|
-- Font Size Slider
|
|
225
232
|
|
|
226
233
|
0.6.3 - 2022-03-18
|
|
227
234
|
-- Fixed issue with some words like سهمیه
|
|
228
|
-
--
|
|
235
|
+
-- Immutable list update
|
|
229
236
|
-- Fixed issue with relative import in Python3
|
|
230
237
|
|
|
231
238
|
0.6.2 - 2022-03-17
|
|
232
|
-
-- Fixed 17: Some addition to
|
|
239
|
+
-- Fixed 17: Some addition to immutable words
|
|
233
240
|
-- Revision in compliance with Python3.10 and PyQt6
|
|
234
241
|
-- Fixed issue with setup
|
|
235
242
|
|
|
@@ -249,5 +256,4 @@
|
|
|
249
256
|
-- Some command line improvements.
|
|
250
257
|
-- More options added to command-line version
|
|
251
258
|
|
|
252
|
-
0.2 - 2012-08-05 Initial release.
|
|
253
|
-
|
|
259
|
+
0.2 - 2012-08-05 Initial release.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-negar
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.12
|
|
4
4
|
Summary: Negar is a spell corrector and Persian text editor
|
|
5
5
|
Home-page: http://github.com/shahinism/python-negar
|
|
6
6
|
Author: Shahin Azad
|
|
@@ -9,20 +9,15 @@ Maintainer: Javad Razavian, Alireza Savand
|
|
|
9
9
|
Maintainer-email: javadr@gmail.com, alireza.savand@gmail.com
|
|
10
10
|
License: GPL
|
|
11
11
|
Keywords: spellcheck Persian editor
|
|
12
|
-
Platform: UNKNOWN
|
|
13
12
|
Classifier: Environment :: Console
|
|
14
13
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
15
14
|
Classifier: Programming Language :: Python
|
|
16
15
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
22
16
|
Requires-Python: >=3.6
|
|
23
17
|
Description-Content-Type: text/markdown
|
|
24
18
|
License-File: LICENSE
|
|
25
19
|
License-File: AUTHORS
|
|
20
|
+
Requires-Dist: regex
|
|
26
21
|
|
|
27
22
|
Negar
|
|
28
23
|
==========
|
|
@@ -114,7 +109,7 @@ result:
|
|
|
114
109
|
* جایگزینی
|
|
115
110
|
+ خط تیرههای پیاپی نظیر (–) و (—) با معادلهای استانداردشان
|
|
116
111
|
+ سه نقطهی پیاپی (…) با کاراکتر استانداردش در زبان فارسی
|
|
117
|
-
+ علایمی نظیر
|
|
112
|
+
+ علایمی نظیر کوتیشن فارسی با گیومه؛ «نگار»
|
|
118
113
|
+ اعداد عربی «۱۲۳۴۵۶۷۸۹۰» و انگلیسی «۱۲۳۴۵۶۷۸۹۰» با معادل فارسی
|
|
119
114
|
+ کاراکترهای غیر فارسی نظیر «، ؛ ٪یهک» با معادلهای فارسی
|
|
120
115
|
|
|
@@ -177,5 +172,3 @@ Both of them are available on PyPI.
|
|
|
177
172
|
<a href="https://github.com/shahinism/python-negar/graphs/contributors">
|
|
178
173
|
<img src="https://contrib.rocks/image?repo=shahinism/python-negar" />
|
|
179
174
|
</a>
|
|
180
|
-
|
|
181
|
-
|
|
@@ -88,7 +88,7 @@ result:
|
|
|
88
88
|
* جایگزینی
|
|
89
89
|
+ خط تیرههای پیاپی نظیر (–) و (—) با معادلهای استانداردشان
|
|
90
90
|
+ سه نقطهی پیاپی (…) با کاراکتر استانداردش در زبان فارسی
|
|
91
|
-
+ علایمی نظیر
|
|
91
|
+
+ علایمی نظیر کوتیشن فارسی با گیومه؛ «نگار»
|
|
92
92
|
+ اعداد عربی «۱۲۳۴۵۶۷۸۹۰» و انگلیسی «۱۲۳۴۵۶۷۸۹۰» با معادل فارسی
|
|
93
93
|
+ کاراکترهای غیر فارسی نظیر «، ؛ ٪یهک» با معادلهای فارسی
|
|
94
94
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import platform
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
|
-
__version__ = "1.2.
|
|
4
|
+
__version__ = "1.2.12"
|
|
5
5
|
|
|
6
|
-
DATAFILE = Path(__file__).parent.absolute() / "data/
|
|
6
|
+
DATAFILE = Path(__file__).parent.absolute() / "data/immutable.words"
|
|
7
7
|
APPDATA = "AppData/Roaming/" if platform.system() == "Windows" else "."
|
|
8
8
|
USERFILE = Path.home() / f"{APPDATA}python-negar"
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@ INFO = f"""قابلیت های ویراستار ' نگار ' -- نسخه {__ver
|
|
|
11
11
|
* جایگزینی
|
|
12
12
|
╛═ خط تیره های پیاپی نظیر (--) و (---) با معادل های استاندارد شان
|
|
13
13
|
╛═ سه نقطه ی پیاپی (...) با کاراکتر استانداردش در زبان فارسی
|
|
14
|
-
╛═ علایمی نظیر
|
|
14
|
+
╛═ علایمی نظیر کوتیشن فارسی با گیومه ؛ 'نگار'
|
|
15
15
|
╛═ اعداد عربی '١٢٣٤٥٦٧٨٩٠' و انگلیسی '1234567890' با معادل فارسی
|
|
16
16
|
╛═ کاراکتر های غیر فارسی نظیر ',;%يةك' با معادل های فارسی
|
|
17
17
|
* تنظیم فاصله
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
|
+
# ruff: noqa: T201
|
|
2
3
|
|
|
3
4
|
import enum
|
|
4
5
|
import re
|
|
@@ -7,26 +8,30 @@ from pathlib import Path
|
|
|
7
8
|
|
|
8
9
|
import regex
|
|
9
10
|
|
|
10
|
-
sys.path.append(
|
|
11
|
-
|
|
11
|
+
sys.path.append(
|
|
12
|
+
Path(__file__).parent.parent.as_posix()
|
|
13
|
+
) # https://stackoverflow.com/questions/16981921
|
|
14
|
+
from negar.constants import DATAFILE, INFO, URLREGX, USERFILE # noqa: E402
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class State(enum.Enum):
|
|
15
18
|
save = 1
|
|
16
19
|
restore = 2
|
|
17
20
|
|
|
21
|
+
|
|
18
22
|
class PersianEditor:
|
|
19
|
-
"""Persian Text Editor for some
|
|
23
|
+
"""Persian Text Editor for some sanitization task called Virastary in Persian."""
|
|
20
24
|
|
|
21
25
|
def __init__(self, text, *args):
|
|
22
26
|
# Check to see if `arg` exists in `args` or not
|
|
23
|
-
parse_args = lambda arg: arg not in args
|
|
24
|
-
self._prepositions =
|
|
25
|
-
"از|در|به|با|بر|برای|بی|درباره|تا|را|جز|بدون|چون|مانند|مثل"
|
|
26
|
-
"|زیر|روی|همراه|مگر|الا|اندر|زی|برت|الا|زی|چو|سوای|پایین"
|
|
27
|
+
parse_args = lambda arg: arg not in args # noqa: E731
|
|
28
|
+
self._prepositions = (
|
|
29
|
+
"از|در|به|با|بر|برای|بی|درباره|تا|را|جز|بدون|چون|مانند|مثل"
|
|
30
|
+
"|زیر|روی|همراه|مگر|الا|اندر|زی|برت|الا|زی|چو|سوای|پایین"
|
|
27
31
|
"|پشت|پهلوی|پس|پیش|بالای|بیرون|درون|توی|غیر|کنار|مقابل|بهر"
|
|
32
|
+
)
|
|
28
33
|
self.text = text
|
|
29
|
-
self._cleanup_zwnj
|
|
34
|
+
self._cleanup_zwnj = False
|
|
30
35
|
# checking for undesired options
|
|
31
36
|
self._aggresive = parse_args("aggresive")
|
|
32
37
|
self._fix_hamzeh = parse_args("fix-hamzeh")
|
|
@@ -48,7 +53,7 @@ class PersianEditor:
|
|
|
48
53
|
self._fix_spacing_for_braces_and_quotes = parse_args("fix-spacing-bq")
|
|
49
54
|
self._trim_leading_trailing_whitespaces = parse_args("trim-lt-whitespaces")
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
ImmutableWords() # to generate the immutable words
|
|
52
57
|
self.cleanup()
|
|
53
58
|
|
|
54
59
|
def cleanup(self):
|
|
@@ -56,8 +61,8 @@ class PersianEditor:
|
|
|
56
61
|
# fix punctuation spaces at first
|
|
57
62
|
# : ; , ! ? and their Persian counterparts should have one space after and no space before
|
|
58
63
|
# An exception is triple dots, which should be handled first
|
|
59
|
-
self.fix_three_dots()
|
|
60
|
-
self.aggressive()
|
|
64
|
+
self.fix_three_dots() if self._fix_three_dots else None
|
|
65
|
+
self.aggressive() if self._aggresive else None
|
|
61
66
|
self.text = re.sub(
|
|
62
67
|
r"[ ]*([…:;,؛،.؟!]{1})[ ]*",
|
|
63
68
|
r"\1 ",
|
|
@@ -79,12 +84,14 @@ class PersianEditor:
|
|
|
79
84
|
self.fix_spacing_for_braces_and_quotes() \
|
|
80
85
|
if self._fix_spacing_for_braces_and_quotes else None
|
|
81
86
|
self.cleanup_redundant_zwnj()
|
|
82
|
-
self.cleanup_spacing()
|
|
87
|
+
self.cleanup_spacing() if self._cleanup_spacing else None
|
|
83
88
|
self.text = re.sub(
|
|
84
89
|
r"…([.؟!])",
|
|
85
90
|
r"… \1",
|
|
86
91
|
self.text,
|
|
87
92
|
)
|
|
93
|
+
if self._trim_leading_trailing_whitespaces:
|
|
94
|
+
self.text = "\n".join([line.strip() for line in self.text.split("\n")])
|
|
88
95
|
self._handle_urls(State.restore)
|
|
89
96
|
return self.text
|
|
90
97
|
|
|
@@ -96,7 +103,7 @@ class PersianEditor:
|
|
|
96
103
|
def _handle_urls(self, state):
|
|
97
104
|
"""Remove URLs and putting them back at the end of the process."""
|
|
98
105
|
if state == State.save:
|
|
99
|
-
self.urls = list(set(re.findall(URLREGX, self.text, re.M|re.I|re.X)))
|
|
106
|
+
self.urls = list(set(re.findall(URLREGX, self.text, re.M | re.I | re.X)))
|
|
100
107
|
self.urls.sort(key=lambda x: len(x), reverse=True)
|
|
101
108
|
for i, url in enumerate(self.urls):
|
|
102
109
|
self.text = regex.sub(rf"{re.escape(url)}", rf"__URL__#{i}__", self.text)
|
|
@@ -123,9 +130,9 @@ class PersianEditor:
|
|
|
123
130
|
--the last one is achievable if hamzeh_with_yeh set.
|
|
124
131
|
"""
|
|
125
132
|
if self._hamzeh_with_yeh:
|
|
126
|
-
self.text = re.sub(r"(\S)(ه[\s]+[یي])(\b)",r"\1هی\3",self.text)
|
|
133
|
+
self.text = re.sub(r"(\S)(ه[\s]+[یي])(\b)", r"\1هی\3", self.text)
|
|
127
134
|
else:
|
|
128
|
-
self.text = re.sub(r"(\S)(ه[\s]+[یي])(\b)",r"\1هٔ\3", self.text)
|
|
135
|
+
self.text = re.sub(r"(\S)(ه[\s]+[یي])(\b)", r"\1هٔ\3", self.text)
|
|
129
136
|
|
|
130
137
|
def cleanup_zwnj(self):
|
|
131
138
|
"""Remove unnecessary ZWNJ that are succeeded/preceded by a space."""
|
|
@@ -138,7 +145,7 @@ class PersianEditor:
|
|
|
138
145
|
|
|
139
146
|
def char_validator(self):
|
|
140
147
|
"""Replace invalid characters with valid ones."""
|
|
141
|
-
bad_chars
|
|
148
|
+
bad_chars = ",;%يةك"
|
|
142
149
|
good_chars = "،؛٪یهک"
|
|
143
150
|
self.text = self.char_translator(bad_chars, good_chars, self.text)
|
|
144
151
|
|
|
@@ -165,25 +172,27 @@ class PersianEditor:
|
|
|
165
172
|
# Avoids to change English numbers in strings like 'Text12', 'Text_12', or 'A4'
|
|
166
173
|
self.text = re.sub(
|
|
167
174
|
r"[۰-۹]+[a-zA-Z_]{1,}[۰-۹]+|[a-zA-Z_]{1,}[۰-۹]+|[۰-۹]+[a-zA-Z_]{1,}",
|
|
168
|
-
lambda m:
|
|
169
|
-
self.char_translator(persian_numbers, english_numbers, m.group()),
|
|
175
|
+
lambda m: self.char_translator(persian_numbers, english_numbers, m.group()),
|
|
170
176
|
self.text,
|
|
171
177
|
)
|
|
172
178
|
|
|
173
179
|
def fix_prefix_spacing(self):
|
|
174
180
|
"""Put ZWNJ between a word and its prefix (mi* nemi* bi* na*)."""
|
|
175
|
-
self.text = re.sub(r"\b(بی|نا)*(\s+)(?!(می)\b)",r"\1", self.text)
|
|
176
|
-
# the following case is for the mi(n.) and
|
|
177
|
-
self.text = re.sub(rf"\b(ن?می)*(\s+)(?!(.|{self._prepositions})\b)",r"\1", self.text)
|
|
181
|
+
self.text = re.sub(r"\b(بی|نا)*(\s+)(?!(می)\b)", r"\1", self.text)
|
|
182
|
+
# the following case is for the mi(n.) and nemi(n.)
|
|
183
|
+
self.text = re.sub(rf"\b(ن?می)*(\s+)(?!(.|{self._prepositions})\b)", r"\1", self.text)
|
|
178
184
|
|
|
179
185
|
def fix_prefix_separate(self):
|
|
180
186
|
"""Put ZWNJ between a word and its prefix (mi* nemi* bi*)."""
|
|
181
187
|
# regx = re.compile(r"\b(بی|ن?می)*([^\[\]\(\)\s]+)") # \b for words like سهمیه
|
|
182
|
-
regx = regex.compile(
|
|
188
|
+
regx = regex.compile(
|
|
189
|
+
r"""
|
|
183
190
|
\b(بی|ن?می)*
|
|
184
191
|
([^\[\]\(\)\s]+)
|
|
185
192
|
(?<!های|هایی|ها|شناس|شناسی|گذار|گذاری)\b
|
|
186
|
-
""",
|
|
193
|
+
""",
|
|
194
|
+
re.VERBOSE,
|
|
195
|
+
) # \b for words like سهمیه
|
|
187
196
|
|
|
188
197
|
# Replace backslashes with a temporary placeholder
|
|
189
198
|
text = self.text.replace("\\", "PN__BACKSLASH__PN")
|
|
@@ -192,10 +201,10 @@ class PersianEditor:
|
|
|
192
201
|
regx_iter = regx.finditer(word)
|
|
193
202
|
for p in regx_iter:
|
|
194
203
|
# Checks that the prefix (mi* nemi* bi*) is part a a word or not, like میلاد.
|
|
195
|
-
if p.group() not in
|
|
204
|
+
if p.group() not in ImmutableWords.get():
|
|
196
205
|
text = re.sub(
|
|
197
|
-
re.escape(
|
|
198
|
-
p.group(1) + "\u200c" + p.group(2)
|
|
206
|
+
re.escape(p.group()),
|
|
207
|
+
p.group(1) + "\u200c" + p.group(2),
|
|
199
208
|
text,
|
|
200
209
|
)
|
|
201
210
|
# Restore the original backslashes
|
|
@@ -213,7 +222,8 @@ class PersianEditor:
|
|
|
213
222
|
|شناس(ی)?
|
|
214
223
|
|گذار(ی)?|گزار(ی)?
|
|
215
224
|
|مند|ور|پور
|
|
216
|
-
)\b""",
|
|
225
|
+
)\b""",
|
|
226
|
+
re.VERBOSE,
|
|
217
227
|
)
|
|
218
228
|
self.text = re.sub(regx, r"\1", self.text)
|
|
219
229
|
|
|
@@ -227,10 +237,14 @@ class PersianEditor:
|
|
|
227
237
|
|
|
228
238
|
def fix_suffix_separate(self):
|
|
229
239
|
"""Put ZWNJ between a word with its suffix (haye, ...)."""
|
|
230
|
-
exag =
|
|
240
|
+
exag = (
|
|
241
|
+
r"""
|
|
231
242
|
تر(ی(ن)?)?|
|
|
232
243
|
[تمش]ان|
|
|
233
|
-
ها(ی(ی|ت|م|ش|تان|شان)?)?|"""
|
|
244
|
+
ها(ی(ی|ت|م|ش|تان|شان)?)?|"""
|
|
245
|
+
if self._exaggerating_zwnj
|
|
246
|
+
else ""
|
|
247
|
+
)
|
|
234
248
|
regx = re.compile(
|
|
235
249
|
rf"""\b(\S+?) # not-greedy fetch to handle some case like هایشان instead شان
|
|
236
250
|
({exag}
|
|
@@ -239,7 +253,8 @@ class PersianEditor:
|
|
|
239
253
|
# ها(ی(ی|ت|م|ش|تان|شان)?)?|
|
|
240
254
|
شناس(ی)?|
|
|
241
255
|
گذار(ی)?|گزار(ی)?
|
|
242
|
-
)\b""",
|
|
256
|
+
)\b""",
|
|
257
|
+
re.VERBOSE,
|
|
243
258
|
)
|
|
244
259
|
# Replace backslashes with a temporary placeholder
|
|
245
260
|
text = self.text.replace("\\", "PN__BACKSLASH__PN")
|
|
@@ -248,9 +263,9 @@ class PersianEditor:
|
|
|
248
263
|
regx_iter = regx.finditer(word)
|
|
249
264
|
for p in regx_iter:
|
|
250
265
|
# Checks that the suffix (tar* haye*) is part of a word or not, like بهتر.
|
|
251
|
-
if p.group() not in
|
|
266
|
+
if p.group() not in ImmutableWords.get():
|
|
252
267
|
text = re.sub(
|
|
253
|
-
re.escape(
|
|
268
|
+
re.escape(p.group()),
|
|
254
269
|
p.group(1) + "\u200c" + p.group(2),
|
|
255
270
|
text,
|
|
256
271
|
)
|
|
@@ -269,9 +284,12 @@ class PersianEditor:
|
|
|
269
284
|
def fix_spacing_for_braces_and_quotes(self):
|
|
270
285
|
"""Fix the braces and quotes spacing problems."""
|
|
271
286
|
# ()[]{}""«» should have one space before and no space after (inside)
|
|
272
|
-
for begin, end in zip(["\(","\[","\{",'"',"«"], ["\)","\]","\}",'"',"»"]):
|
|
273
|
-
self.text = re.sub(
|
|
274
|
-
r" \1\2\3 ", self.text
|
|
287
|
+
for begin, end in zip(["\(", "\[", "\{", '"', "«"], ["\)", "\]", "\}", '"', "»"]):
|
|
288
|
+
self.text = re.sub(
|
|
289
|
+
rf"[ ]*({begin})\s*([^{end}]+?)\s*?({end})[ ]*", r" \1\2\3 ", self.text
|
|
290
|
+
)
|
|
291
|
+
# self.text = re.sub(rf"^[ ]*(.*)[ ]*$",
|
|
292
|
+
# r"\1", self.text, flags=re.MULTILINE)
|
|
275
293
|
# # : ; , ! ? and their Persian counterparts should have one space after and no space before
|
|
276
294
|
self.text = re.sub(
|
|
277
295
|
r"[ ]*([:;,؛،.؟!]{1})[ ]*",
|
|
@@ -314,8 +332,8 @@ class PersianEditor:
|
|
|
314
332
|
return newstring
|
|
315
333
|
|
|
316
334
|
|
|
317
|
-
class
|
|
318
|
-
words = set()
|
|
335
|
+
class ImmutableWords:
|
|
336
|
+
words = set() # a set storing all immutable words
|
|
319
337
|
|
|
320
338
|
@classmethod
|
|
321
339
|
def __init__(cls):
|
|
@@ -328,31 +346,35 @@ class UnTouchable:
|
|
|
328
346
|
|
|
329
347
|
@classmethod
|
|
330
348
|
def add(cls, word_list):
|
|
331
|
-
with (USERFILE/"
|
|
349
|
+
with (USERFILE / "immutable.words").open("a", encoding="utf8") as f:
|
|
332
350
|
for word in word_list:
|
|
333
351
|
if word not in cls.words:
|
|
334
|
-
f.write(word+"\n")
|
|
352
|
+
f.write(word + "\n")
|
|
335
353
|
cls.words.add(word)
|
|
336
354
|
|
|
337
355
|
@classmethod
|
|
338
356
|
def generate(cls):
|
|
339
|
-
"""Make a list from
|
|
357
|
+
"""Make a list from immutable words.
|
|
340
358
|
|
|
341
|
-
A Unicode list from 'data/
|
|
359
|
+
A Unicode list from 'data/immutable.words' and '~/.python-negar/immutable.words'
|
|
342
360
|
containing such words like 'بهتر' or 'میلاد' won't receive any modifications.
|
|
343
361
|
"""
|
|
344
362
|
with DATAFILE.open(encoding="utf8") as f:
|
|
345
363
|
for line in f:
|
|
346
364
|
cls.words.add(line.strip())
|
|
347
365
|
try:
|
|
348
|
-
with
|
|
366
|
+
# for compatibility with previous versions, since immutable.words was untouchable.dat before ver 1.2.10
|
|
367
|
+
if (USERFILE / "untouchable.dat").exists():
|
|
368
|
+
(USERFILE / "untouchable.dat").rename(USERFILE / "immutable.words")
|
|
369
|
+
with (USERFILE / "immutable.words").open(encoding="utf8") as f:
|
|
349
370
|
for line in f:
|
|
350
371
|
cls.words.add(line.strip())
|
|
351
372
|
except FileNotFoundError:
|
|
352
373
|
pass
|
|
353
374
|
|
|
375
|
+
|
|
354
376
|
if __name__ == "__main__":
|
|
355
|
-
print(
|
|
377
|
+
print("I'm a module. If you'd like the GUI, use ``negar'' instead. ;-)")
|
|
356
378
|
|
|
357
379
|
print(f"""\nUsage:
|
|
358
380
|
from virastar import PersianEditor
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-negar
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.12
|
|
4
4
|
Summary: Negar is a spell corrector and Persian text editor
|
|
5
5
|
Home-page: http://github.com/shahinism/python-negar
|
|
6
6
|
Author: Shahin Azad
|
|
@@ -9,20 +9,15 @@ Maintainer: Javad Razavian, Alireza Savand
|
|
|
9
9
|
Maintainer-email: javadr@gmail.com, alireza.savand@gmail.com
|
|
10
10
|
License: GPL
|
|
11
11
|
Keywords: spellcheck Persian editor
|
|
12
|
-
Platform: UNKNOWN
|
|
13
12
|
Classifier: Environment :: Console
|
|
14
13
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
15
14
|
Classifier: Programming Language :: Python
|
|
16
15
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
22
16
|
Requires-Python: >=3.6
|
|
23
17
|
Description-Content-Type: text/markdown
|
|
24
18
|
License-File: LICENSE
|
|
25
19
|
License-File: AUTHORS
|
|
20
|
+
Requires-Dist: regex
|
|
26
21
|
|
|
27
22
|
Negar
|
|
28
23
|
==========
|
|
@@ -114,7 +109,7 @@ result:
|
|
|
114
109
|
* جایگزینی
|
|
115
110
|
+ خط تیرههای پیاپی نظیر (–) و (—) با معادلهای استانداردشان
|
|
116
111
|
+ سه نقطهی پیاپی (…) با کاراکتر استانداردش در زبان فارسی
|
|
117
|
-
+ علایمی نظیر
|
|
112
|
+
+ علایمی نظیر کوتیشن فارسی با گیومه؛ «نگار»
|
|
118
113
|
+ اعداد عربی «۱۲۳۴۵۶۷۸۹۰» و انگلیسی «۱۲۳۴۵۶۷۸۹۰» با معادل فارسی
|
|
119
114
|
+ کاراکترهای غیر فارسی نظیر «، ؛ ٪یهک» با معادلهای فارسی
|
|
120
115
|
|
|
@@ -177,5 +172,3 @@ Both of them are available on PyPI.
|
|
|
177
172
|
<a href="https://github.com/shahinism/python-negar/graphs/contributors">
|
|
178
173
|
<img src="https://contrib.rocks/image?repo=shahinism/python-negar" />
|
|
179
174
|
</a>
|
|
180
|
-
|
|
181
|
-
|
|
@@ -8,11 +8,11 @@ negar/__init__.py
|
|
|
8
8
|
negar/constants.py
|
|
9
9
|
negar/gui.py
|
|
10
10
|
negar/virastar.py
|
|
11
|
-
negar/data/
|
|
12
|
-
negar/data/untouchable.dat
|
|
11
|
+
negar/data/immutable.words
|
|
13
12
|
python_negar.egg-info/PKG-INFO
|
|
14
13
|
python_negar.egg-info/SOURCES.txt
|
|
15
14
|
python_negar.egg-info/dependency_links.txt
|
|
16
15
|
python_negar.egg-info/entry_points.txt
|
|
17
16
|
python_negar.egg-info/requires.txt
|
|
18
|
-
python_negar.egg-info/top_level.txt
|
|
17
|
+
python_negar.egg-info/top_level.txt
|
|
18
|
+
tests/test_unittest.py
|
|
@@ -21,7 +21,7 @@ setup(
|
|
|
21
21
|
"regex",
|
|
22
22
|
],
|
|
23
23
|
package_dir={"negar": "negar"},
|
|
24
|
-
package_data={"negar/data": ["data/*.
|
|
24
|
+
package_data={"negar/data": ["data/*.words"]},
|
|
25
25
|
description="Negar is a spell corrector and Persian text editor",
|
|
26
26
|
license="GPL",
|
|
27
27
|
keywords="spellcheck Persian editor",
|
|
@@ -39,11 +39,6 @@ setup(
|
|
|
39
39
|
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
|
40
40
|
"Programming Language :: Python",
|
|
41
41
|
"Programming Language :: Python :: 3",
|
|
42
|
-
"Programming Language :: Python :: 3.6",
|
|
43
|
-
"Programming Language :: Python :: 3.7",
|
|
44
|
-
"Programming Language :: Python :: 3.8",
|
|
45
|
-
"Programming Language :: Python :: 3.9",
|
|
46
|
-
"Programming Language :: Python :: 3.10",
|
|
47
42
|
],
|
|
48
43
|
|
|
49
44
|
)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import functools
|
|
3
|
+
from negar.virastar import PersianEditor
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Test(unittest.TestCase):
|
|
7
|
+
def _assertEqual(message=""):
|
|
8
|
+
def decorator(func):
|
|
9
|
+
@functools.wraps(func)
|
|
10
|
+
def wrapper(self, *args, **kwargs):
|
|
11
|
+
func(self, *args, **kwargs)
|
|
12
|
+
return self.assertEqual(f"{PersianEditor(self.input_)}", self.output_, message)
|
|
13
|
+
return wrapper
|
|
14
|
+
return decorator
|
|
15
|
+
|
|
16
|
+
# @unittest.skip("")
|
|
17
|
+
@_assertEqual("Trim Leading Trailing Whitespaces")
|
|
18
|
+
def test_trim_leading_trailing_whitespaces(self):
|
|
19
|
+
self.input_ = "فضا های خالی بیش از حد"
|
|
20
|
+
self.output_ = "فضاهای خالی بیش از حد"
|
|
21
|
+
|
|
22
|
+
@_assertEqual("Fix Hamzeh")
|
|
23
|
+
def test_fix_hamzeh(self):
|
|
24
|
+
self.input_ = "کلماتی که با 'ی' پسوند همراه هستند مانند 'همه ی ' -- و البته امکان جایگزینی آن با حمزه 'ء' ( در صورت انتخاب کاربر )" # noqa: E501
|
|
25
|
+
self.output_ = "کلماتی که با «ی» پسوند همراه هستند مانند «همهی» – و البته امکان جایگزینی آن با حمزه «ء» (در صورت انتخاب کاربر)" # noqa: E501
|
|
26
|
+
|
|
27
|
+
@_assertEqual("Numbers as a Version -- Triple Dots")
|
|
28
|
+
def test_versioning_numbers_triple(self):
|
|
29
|
+
"""There is no space between dots of version number!."""
|
|
30
|
+
self.input_ = "نسخه 1.2.4"
|
|
31
|
+
self.output_ = "نسخه ۱.۲.۴"
|
|
32
|
+
|
|
33
|
+
@_assertEqual("Numbers as a Version -- Double Dots")
|
|
34
|
+
def test_versioning_numbers_double(self):
|
|
35
|
+
"""There is no space between dots of version number!."""
|
|
36
|
+
self.input_ = "نسخه 1.2"
|
|
37
|
+
self.output_ = "نسخه ۱.۲"
|
|
38
|
+
|
|
39
|
+
@_assertEqual("Consecutive Dashes")
|
|
40
|
+
def test_consecutive_dashes(self):
|
|
41
|
+
self.input_ = "خط تیره های پیاپی نظیر (--) و (---) با معادل های استاندارد شان"
|
|
42
|
+
self.output_ = "خط تیرههای پیاپی نظیر (–) و (—) با معادلهای استانداردشان"
|
|
43
|
+
|
|
44
|
+
@_assertEqual("Triple Dots I")
|
|
45
|
+
def test_triple_dots_i(self):
|
|
46
|
+
self.input_ = "سه نقطه ی پیاپی (...) با کاراکتر استانداردش در زبان فارسی"
|
|
47
|
+
self.output_ = "سه نقطهی پیاپی (…) با کاراکتر استانداردش در زبان فارسی"
|
|
48
|
+
|
|
49
|
+
@_assertEqual("Triple Dots II")
|
|
50
|
+
def test_triple_dots_ii(self):
|
|
51
|
+
self.input_ = "پرتره ، طبیعت و غیره یا پرتره ، طبیعت و .... ؟"
|
|
52
|
+
self.output_ = "پرتره، طبیعت و غیره یا پرتره، طبیعت و… ؟"
|
|
53
|
+
|
|
54
|
+
@_assertEqual("Persian Quotations")
|
|
55
|
+
def test_persian_quotations(self):
|
|
56
|
+
self.input_ = "علایمی نظیر کتیشن فارسی با گیومه ؛ 'نگار'"
|
|
57
|
+
self.output_ = "علایمی نظیر کتیشن فارسی با گیومه؛ «نگار»"
|
|
58
|
+
|
|
59
|
+
@_assertEqual("Persian Numbers")
|
|
60
|
+
def test_persian_numbers(self):
|
|
61
|
+
self.input_ = "اعداد عربی '١٢٣٤٥٦٧٨٩٠' و انگلیسی '1234567890' با معادل فارسی"
|
|
62
|
+
self.output_ = "اعداد عربی «۱۲۳۴۵۶۷۸۹۰» و انگلیسی «۱۲۳۴۵۶۷۸۹۰» با معادل فارسی"
|
|
63
|
+
|
|
64
|
+
@_assertEqual("Non-Persian Characters")
|
|
65
|
+
def test_non_persian_characters(self):
|
|
66
|
+
self.input_ = "کاراکتر های غیر فارسی نظیر ',;%يةك' با معادل های فارسی"
|
|
67
|
+
self.output_ = "کاراکترهای غیر فارسی نظیر «، ؛ ٪یهک» با معادلهای فارسی"
|
|
68
|
+
|
|
69
|
+
@_assertEqual("Persian-Yeh as a Kasreh")
|
|
70
|
+
def test_persian_yeh_as_a_kasreh(self):
|
|
71
|
+
self.input_ = "کلماتی که با 'ی' پسوند همراه هستند مانند 'همه ی ' -- و البته امکان جایگزینی آن با حمزه 'ء' ( در صورت انتخاب کاربر )"
|
|
72
|
+
self.output_ = "کلماتی که با «ی» پسوند همراه هستند مانند «همهی» – و البته امکان جایگزینی آن با حمزه «ء» (در صورت انتخاب کاربر)"
|
|
73
|
+
|
|
74
|
+
@_assertEqual("Fix Parantheses")
|
|
75
|
+
def test_fix_parantheses(self):
|
|
76
|
+
self.input_ = "پرانتز ها یا دیگر علایم ؛ ( نگار )"
|
|
77
|
+
self.output_ = "پرانتزها یا دیگر علایم؛ (نگار)"
|
|
78
|
+
|
|
79
|
+
@_assertEqual("Fix Punctuations")
|
|
80
|
+
def test_fix_punctuation(self):
|
|
81
|
+
self.input_ = "علائم نقطهگذاری ؛ بدون فاصله از قبل و با یک فاصله از بعد به استثنای اعداد اعشاری/نسخه نرمافزاری مانند 12.4/1.2.4"
|
|
82
|
+
self.output_ = "علائم نقطهگذاری؛ بدون فاصله از قبل و با یک فاصله از بعد به استثنای اعداد اعشاری/نسخه نرمافزاری مانند ۱۲.۴/۱.۲.۴"
|
|
83
|
+
|
|
84
|
+
@_assertEqual("Fix Prefix ZWNJ")
|
|
85
|
+
def test_fix_prefix_ZWNJ(self):
|
|
86
|
+
self.input_ = r"در پیشوند کلمات با نیمفاصله نظیر ' می شود '، ' میشود '، ' بی شک '، ' بیشک ' , ' خانه اش '، ' وظیفه شناس ' ، ' کمک تان ' و یا ' نمیرود '"
|
|
87
|
+
self.output_ = "در پیشوند کلمات با نیمفاصله نظیر «میشود»، «میشود»، «بیشک»، «بیشک»، «خانهاش»، «وظیفهشناس»، «کمکتان» و یا «نمیرود»"
|
|
88
|
+
|
|
89
|
+
@_assertEqual("Fix Suffix ZWNJ I")
|
|
90
|
+
def test_fix_suffix_ZWNJ_I(self):
|
|
91
|
+
self.input_ = r"در پسوند کلمات با نیمفاصله نظیر کتابها، خوشترین -- و البته امکان عدم تنظیم (در صورت انتخاب کاربر)"
|
|
92
|
+
self.output_ = "در پسوند کلمات با نیمفاصله نظیر کتابها، خوشترین – و البته امکان عدم تنظیم (در صورت انتخاب کاربر)"
|
|
93
|
+
|
|
94
|
+
@_assertEqual("Fix Redundant Glyphs")
|
|
95
|
+
def test_cleanup_redundant_glyphs(self):
|
|
96
|
+
self.input_ = "استفاده ی بیش از یک علامت ؟؟؟؟ یا !!!"
|
|
97
|
+
self.output_ = "استفادهی بیش از یک علامت؟ یا!"
|
|
98
|
+
|
|
99
|
+
@_assertEqual("Cleanup Kashidas")
|
|
100
|
+
def test_cleanup_kashidas(self):
|
|
101
|
+
self.input_ = "کشیـــــــــدگـــــــــــــــــی در کــــــــــــلمــــات"
|
|
102
|
+
self.output_ = "کشیدگی در کلمات"
|
|
103
|
+
|
|
104
|
+
@_assertEqual("Cleanup Extra Spaces")
|
|
105
|
+
def test_cleanup_extra_spaces(self):
|
|
106
|
+
self.input_ = "فضا های خالی بیش از حد"
|
|
107
|
+
self.output_ = "فضاهای خالی بیش از حد"
|
|
108
|
+
|
|
109
|
+
@_assertEqual("Immutable Words I")
|
|
110
|
+
def test_immutable_words_i(self):
|
|
111
|
+
self.input_ = "تنها ترین خدمتگزار (تنها ترین خدمتگزار)"
|
|
112
|
+
self.output_ = "تنهاترین خدمتگزار (تنهاترین خدمتگزار)"
|
|
113
|
+
|
|
114
|
+
@_assertEqual("Immutable Words II")
|
|
115
|
+
def test_immutable_words_ii(self):
|
|
116
|
+
self.input_ = "تنها ترین خدمتگزار (تنها ترین خدمتگزار)"
|
|
117
|
+
self.output_ = "تنهاترین خدمتگزار (تنهاترین خدمتگزار)"
|
|
118
|
+
|
|
119
|
+
@_assertEqual("Fix Suffix ZWNJ II")
|
|
120
|
+
def test_fix_suffix_ZWNJ_II(self):
|
|
121
|
+
self.input_ = "بیستم ماه میلادی"
|
|
122
|
+
self.output_ = "بیستم ماه میلادی"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/python-negar-1.2.9/negar/data/untouchable.dat → /python_negar-1.2.12/negar/data/immutable.words
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|