arabcheck 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.
- arabcheck-0.1.0/LICENSE +21 -0
- arabcheck-0.1.0/PKG-INFO +247 -0
- arabcheck-0.1.0/README.md +224 -0
- arabcheck-0.1.0/pyproject.toml +35 -0
- arabcheck-0.1.0/setup.cfg +4 -0
- arabcheck-0.1.0/src/arabcheck/__init__.py +5 -0
- arabcheck-0.1.0/src/arabcheck/__main__.py +5 -0
- arabcheck-0.1.0/src/arabcheck/cli.py +59 -0
- arabcheck-0.1.0/src/arabcheck/core.py +49 -0
- arabcheck-0.1.0/src/arabcheck/patterns.py +27 -0
- arabcheck-0.1.0/src/arabcheck.egg-info/PKG-INFO +247 -0
- arabcheck-0.1.0/src/arabcheck.egg-info/SOURCES.txt +16 -0
- arabcheck-0.1.0/src/arabcheck.egg-info/dependency_links.txt +1 -0
- arabcheck-0.1.0/src/arabcheck.egg-info/entry_points.txt +2 -0
- arabcheck-0.1.0/src/arabcheck.egg-info/requires.txt +3 -0
- arabcheck-0.1.0/src/arabcheck.egg-info/top_level.txt +1 -0
- arabcheck-0.1.0/tests/test_cli.py +104 -0
- arabcheck-0.1.0/tests/test_core.py +42 -0
arabcheck-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mohamed Kamal Sallih
|
|
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.
|
arabcheck-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: arabcheck
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight toolkit and CLI for cleaning, normalizing, and auditing Arabic text.
|
|
5
|
+
Author-email: Mohamed Kamal Salih Mahmod <102423366+MOHAMEDKAMALSALLIH@users.noreply.github.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/MOHAMEDKAMALSALLIH/arabcheck
|
|
8
|
+
Project-URL: Repository, https://github.com/MOHAMEDKAMALSALLIH/arabcheck
|
|
9
|
+
Project-URL: Issues, https://github.com/MOHAMEDKAMALSALLIH/arabcheck/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/MOHAMEDKAMALSALLIH/arabcheck/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Releases, https://github.com/MOHAMEDKAMALSALLIH/arabcheck/releases
|
|
12
|
+
Keywords: arabic,nlp,text-cleaning,tashkeel
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Natural Language :: Arabic
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# ArabCheck ๐
|
|
25
|
+
|
|
26
|
+
> A lightweight, open-source toolkit and CLI for cleaning, normalizing, and auditing Arabic text for AI and NLP workflows.
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+

|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Why ArabCheck?
|
|
35
|
+
|
|
36
|
+
Arabic text data often contains noise that breaks NLP pipelines:
|
|
37
|
+
|
|
38
|
+
- **Unicode variants** โ `ุฃ` / `ุฅ` / `ุข` / `ุง` / `ูฑ` all represent alif
|
|
39
|
+
- **Diacritics (Tashkeel)** โ fatha, damma, shadda, tanween
|
|
40
|
+
- **Tatweel (Kashida)** โ decorative stretching characters `ููููู`
|
|
41
|
+
- **Quranic marks** and extra whitespace
|
|
42
|
+
|
|
43
|
+
ArabCheck makes cleaning and auditing this data a one-liner โ with full transparency and configurable operations.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- ๐ **Tashkeel removal** โ Harakat + Quranic marks
|
|
50
|
+
- ๐ค **Character normalization** โ Alif, Yaa, Hamza, Taa Marbuta
|
|
51
|
+
- ใฐ๏ธ **Tatweel removal** โ Kashida stretching characters
|
|
52
|
+
- ๐งน **Text cleaning** โ Whitespace normalization
|
|
53
|
+
- ๐ **Grammar audit** โ Detect common hamzat qat/wasl errors
|
|
54
|
+
- ๐ **File + stdin support**
|
|
55
|
+
- ๐ค **JSON output** for CI/CD pipelines
|
|
56
|
+
- ๐งฉ **Extensible** โ easy to add new rules
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://github.com/MOHAMEDKAMALSALLIH/arabcheck.git
|
|
64
|
+
cd arabcheck
|
|
65
|
+
pip install -e .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Requirements: Python 3.8+ โ no external dependencies.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
Quick Start
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
arabcheck "ุงููููุตูู ุงูุนูุฑูุจูููู ูููุชููุฌูุฑูุจูุฉ" --clean
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Input:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
ุงููููุตูู ุงูุนูุฑูุจูููู ูููุชููุฌูุฑูุจูุฉ
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Output:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
ุงููุต ุงูุนุฑุจู ููุชุฌุฑุจุฉ
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
Usage Examples
|
|
93
|
+
|
|
94
|
+
1. Clean text
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
arabcheck "ุงูุนูุฑูุจููููุฉู ููู ููุบูุฉู ุฌูู
ููููุฉู" --clean
|
|
98
|
+
# โ ุงูุนุฑุจูุฉ ูุบุฉ ุฌู
ููุฉ
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
2. Normalize characters
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
arabcheck "ุฃุญู
ุฏ ุฅุจุฑุงููู
ุขู
ู" --normalize
|
|
105
|
+
# โ ุงุญู
ุฏ ุงุจุฑุงููู
ุงู
ู
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
โ ๏ธ Warning: Normalization loses linguistic information. Use it for search, indexing, or NLP pipelines only.
|
|
109
|
+
|
|
110
|
+
3. Audit text
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
arabcheck "ุงูุฃู
ุฑ ุจุงูุฃู
ุฑ" --audit
|
|
114
|
+
# โ ๏ธ ุงุญุชู
ุงู ุฎุทุฃ: 'ุงูุฃู
ุฑ' ุชุจุฏุฃ ุจู 'ุงู' + ูู
ุฒุฉ ูุทุน.
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
4. JSON output (for automation)
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
arabcheck "ุงููููุตูู" --clean --json
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"input": "ุงููููุตูู",
|
|
126
|
+
"result": "ุงููุต",
|
|
127
|
+
"issues": [],
|
|
128
|
+
"meta": {
|
|
129
|
+
"cleaned": true,
|
|
130
|
+
"normalized": false,
|
|
131
|
+
"audited": false,
|
|
132
|
+
"version": "0.1.0"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
5. Read from file
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
arabcheck --file dataset.txt --clean
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
6. From stdin
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
cat article.txt | arabcheck --clean
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
CLI Reference
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
usage: arabcheck [-h] [-f FILE] [-c] [-n] [-a] [-j] [-q] [-V] [text]
|
|
155
|
+
|
|
156
|
+
positional arguments:
|
|
157
|
+
text Text to process
|
|
158
|
+
|
|
159
|
+
options:
|
|
160
|
+
-h, --help Show help
|
|
161
|
+
-f, --file FILE Read text from file
|
|
162
|
+
-c, --clean Remove tashkeel, tatweel and extra whitespace
|
|
163
|
+
-n, --normalize Normalize letters (alif, yaa, etc.)
|
|
164
|
+
-a, --audit Audit common spelling issues
|
|
165
|
+
-j, --json Output as JSON
|
|
166
|
+
-q, --quiet Suppress text output
|
|
167
|
+
-V, --version Show version
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Exit Codes
|
|
171
|
+
|
|
172
|
+
Code Meaning
|
|
173
|
+
0 Success, no issues
|
|
174
|
+
1 Issues found (with --audit)
|
|
175
|
+
2 Input error
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
Use as a Library
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from arabcheck import ArabCheck
|
|
183
|
+
|
|
184
|
+
checker = ArabCheck()
|
|
185
|
+
|
|
186
|
+
# Clean
|
|
187
|
+
text = checker.clean_text("ุงููููุตูู ุงูุนูุฑูุจูููู ููู")
|
|
188
|
+
print(text) # โ ุงููุต ุงูุนุฑุจู
|
|
189
|
+
|
|
190
|
+
# Normalize
|
|
191
|
+
print(checker.normalize("ุฃุญู
ุฏ ุฅุจุฑุงููู
"))
|
|
192
|
+
# โ ุงุญู
ุฏ ุงุจุฑุงููู
|
|
193
|
+
|
|
194
|
+
# Audit
|
|
195
|
+
issues = checker.audit("ุงูุฃู
ุฑ ุจุงูุฃู
ุฑ")
|
|
196
|
+
for issue in issues:
|
|
197
|
+
print(issue["message"])
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
Testing
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
pip install -e ".[dev]"
|
|
206
|
+
pytest
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
Roadmap
|
|
212
|
+
|
|
213
|
+
โ Tashkeel & Tatweel removal
|
|
214
|
+
โ Character normalization
|
|
215
|
+
โ File + stdin support
|
|
216
|
+
โ JSON output
|
|
217
|
+
โ Exit codes for CI/CD
|
|
218
|
+
โ Grammar audit (hamzat qat/wasl)
|
|
219
|
+
โ Extended audit rules
|
|
220
|
+
โ Dataset loading (CSV, JSONL)
|
|
221
|
+
โ Duplicate detection
|
|
222
|
+
โ Text quality statistics
|
|
223
|
+
โ Publish on PyPI
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
Contributing
|
|
228
|
+
|
|
229
|
+
Contributions, issues, and feature requests are welcome! See CONTRIBUTING.md for guidelines.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
Releases
|
|
234
|
+
|
|
235
|
+
See Releases for version history.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
License
|
|
240
|
+
|
|
241
|
+
MIT โ see LICENSE for details.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
<p align="center">
|
|
246
|
+
Made with โค๏ธ for the Arabic NLP community
|
|
247
|
+
</p>
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# ArabCheck ๐
|
|
2
|
+
|
|
3
|
+
> A lightweight, open-source toolkit and CLI for cleaning, normalizing, and auditing Arabic text for AI and NLP workflows.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Why ArabCheck?
|
|
12
|
+
|
|
13
|
+
Arabic text data often contains noise that breaks NLP pipelines:
|
|
14
|
+
|
|
15
|
+
- **Unicode variants** โ `ุฃ` / `ุฅ` / `ุข` / `ุง` / `ูฑ` all represent alif
|
|
16
|
+
- **Diacritics (Tashkeel)** โ fatha, damma, shadda, tanween
|
|
17
|
+
- **Tatweel (Kashida)** โ decorative stretching characters `ููููู`
|
|
18
|
+
- **Quranic marks** and extra whitespace
|
|
19
|
+
|
|
20
|
+
ArabCheck makes cleaning and auditing this data a one-liner โ with full transparency and configurable operations.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- ๐ **Tashkeel removal** โ Harakat + Quranic marks
|
|
27
|
+
- ๐ค **Character normalization** โ Alif, Yaa, Hamza, Taa Marbuta
|
|
28
|
+
- ใฐ๏ธ **Tatweel removal** โ Kashida stretching characters
|
|
29
|
+
- ๐งน **Text cleaning** โ Whitespace normalization
|
|
30
|
+
- ๐ **Grammar audit** โ Detect common hamzat qat/wasl errors
|
|
31
|
+
- ๐ **File + stdin support**
|
|
32
|
+
- ๐ค **JSON output** for CI/CD pipelines
|
|
33
|
+
- ๐งฉ **Extensible** โ easy to add new rules
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/MOHAMEDKAMALSALLIH/arabcheck.git
|
|
41
|
+
cd arabcheck
|
|
42
|
+
pip install -e .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Requirements: Python 3.8+ โ no external dependencies.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
Quick Start
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
arabcheck "ุงููููุตูู ุงูุนูุฑูุจูููู ูููุชููุฌูุฑูุจูุฉ" --clean
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Input:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
ุงููููุตูู ุงูุนูุฑูุจูููู ูููุชููุฌูุฑูุจูุฉ
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Output:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
ุงููุต ุงูุนุฑุจู ููุชุฌุฑุจุฉ
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
Usage Examples
|
|
70
|
+
|
|
71
|
+
1. Clean text
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
arabcheck "ุงูุนูุฑูุจููููุฉู ููู ููุบูุฉู ุฌูู
ููููุฉู" --clean
|
|
75
|
+
# โ ุงูุนุฑุจูุฉ ูุบุฉ ุฌู
ููุฉ
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
2. Normalize characters
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
arabcheck "ุฃุญู
ุฏ ุฅุจุฑุงููู
ุขู
ู" --normalize
|
|
82
|
+
# โ ุงุญู
ุฏ ุงุจุฑุงููู
ุงู
ู
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
โ ๏ธ Warning: Normalization loses linguistic information. Use it for search, indexing, or NLP pipelines only.
|
|
86
|
+
|
|
87
|
+
3. Audit text
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
arabcheck "ุงูุฃู
ุฑ ุจุงูุฃู
ุฑ" --audit
|
|
91
|
+
# โ ๏ธ ุงุญุชู
ุงู ุฎุทุฃ: 'ุงูุฃู
ุฑ' ุชุจุฏุฃ ุจู 'ุงู' + ูู
ุฒุฉ ูุทุน.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
4. JSON output (for automation)
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
arabcheck "ุงููููุตูู" --clean --json
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"input": "ุงููููุตูู",
|
|
103
|
+
"result": "ุงููุต",
|
|
104
|
+
"issues": [],
|
|
105
|
+
"meta": {
|
|
106
|
+
"cleaned": true,
|
|
107
|
+
"normalized": false,
|
|
108
|
+
"audited": false,
|
|
109
|
+
"version": "0.1.0"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
5. Read from file
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
arabcheck --file dataset.txt --clean
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
6. From stdin
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
cat article.txt | arabcheck --clean
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
CLI Reference
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
usage: arabcheck [-h] [-f FILE] [-c] [-n] [-a] [-j] [-q] [-V] [text]
|
|
132
|
+
|
|
133
|
+
positional arguments:
|
|
134
|
+
text Text to process
|
|
135
|
+
|
|
136
|
+
options:
|
|
137
|
+
-h, --help Show help
|
|
138
|
+
-f, --file FILE Read text from file
|
|
139
|
+
-c, --clean Remove tashkeel, tatweel and extra whitespace
|
|
140
|
+
-n, --normalize Normalize letters (alif, yaa, etc.)
|
|
141
|
+
-a, --audit Audit common spelling issues
|
|
142
|
+
-j, --json Output as JSON
|
|
143
|
+
-q, --quiet Suppress text output
|
|
144
|
+
-V, --version Show version
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Exit Codes
|
|
148
|
+
|
|
149
|
+
Code Meaning
|
|
150
|
+
0 Success, no issues
|
|
151
|
+
1 Issues found (with --audit)
|
|
152
|
+
2 Input error
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
Use as a Library
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from arabcheck import ArabCheck
|
|
160
|
+
|
|
161
|
+
checker = ArabCheck()
|
|
162
|
+
|
|
163
|
+
# Clean
|
|
164
|
+
text = checker.clean_text("ุงููููุตูู ุงูุนูุฑูุจูููู ููู")
|
|
165
|
+
print(text) # โ ุงููุต ุงูุนุฑุจู
|
|
166
|
+
|
|
167
|
+
# Normalize
|
|
168
|
+
print(checker.normalize("ุฃุญู
ุฏ ุฅุจุฑุงููู
"))
|
|
169
|
+
# โ ุงุญู
ุฏ ุงุจุฑุงููู
|
|
170
|
+
|
|
171
|
+
# Audit
|
|
172
|
+
issues = checker.audit("ุงูุฃู
ุฑ ุจุงูุฃู
ุฑ")
|
|
173
|
+
for issue in issues:
|
|
174
|
+
print(issue["message"])
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
Testing
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
pip install -e ".[dev]"
|
|
183
|
+
pytest
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
Roadmap
|
|
189
|
+
|
|
190
|
+
โ Tashkeel & Tatweel removal
|
|
191
|
+
โ Character normalization
|
|
192
|
+
โ File + stdin support
|
|
193
|
+
โ JSON output
|
|
194
|
+
โ Exit codes for CI/CD
|
|
195
|
+
โ Grammar audit (hamzat qat/wasl)
|
|
196
|
+
โ Extended audit rules
|
|
197
|
+
โ Dataset loading (CSV, JSONL)
|
|
198
|
+
โ Duplicate detection
|
|
199
|
+
โ Text quality statistics
|
|
200
|
+
โ Publish on PyPI
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
Contributing
|
|
205
|
+
|
|
206
|
+
Contributions, issues, and feature requests are welcome! See CONTRIBUTING.md for guidelines.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
Releases
|
|
211
|
+
|
|
212
|
+
See Releases for version history.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
License
|
|
217
|
+
|
|
218
|
+
MIT โ see LICENSE for details.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
<p align="center">
|
|
223
|
+
Made with โค๏ธ for the Arabic NLP community
|
|
224
|
+
</p>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "arabcheck"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Lightweight toolkit and CLI for cleaning, normalizing, and auditing Arabic text."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Mohamed Kamal Salih Mahmod", email = "102423366+MOHAMEDKAMALSALLIH@users.noreply.github.com" }]
|
|
13
|
+
keywords = ["arabic", "nlp", "text-cleaning", "tashkeel"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Natural Language :: Arabic",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
]
|
|
20
|
+
dependencies = []
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
dev = ["pytest>=7"]
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://github.com/MOHAMEDKAMALSALLIH/arabcheck"
|
|
26
|
+
Repository = "https://github.com/MOHAMEDKAMALSALLIH/arabcheck"
|
|
27
|
+
Issues = "https://github.com/MOHAMEDKAMALSALLIH/arabcheck/issues"
|
|
28
|
+
Changelog = "https://github.com/MOHAMEDKAMALSALLIH/arabcheck/blob/main/CHANGELOG.md"
|
|
29
|
+
Releases = "https://github.com/MOHAMEDKAMALSALLIH/arabcheck/releases"
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
arabcheck = "arabcheck.cli:main"
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.packages.find]
|
|
35
|
+
where = ["src"]
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""ูุงุฌูุฉ ุณุทุฑ ุงูุฃูุงู
ุฑ."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from . import __version__
|
|
8
|
+
from .core import ArabCheck
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def read_input(args, parser):
|
|
12
|
+
if args.file:
|
|
13
|
+
try:
|
|
14
|
+
return args.file.read_text(encoding="utf-8")
|
|
15
|
+
except FileNotFoundError:
|
|
16
|
+
parser.error(f"ุงูู
ูู ุบูุฑ ู
ูุฌูุฏ: {args.file}")
|
|
17
|
+
if args.text:
|
|
18
|
+
return args.text
|
|
19
|
+
if not sys.stdin.isatty():
|
|
20
|
+
return sys.stdin.read()
|
|
21
|
+
parser.error("ูุงุฒู
ุชู
ุฑูุฑ ูุตุงูุ ุฃู --fileุ ุฃู stdin.")
|
|
22
|
+
return ""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def build_parser():
|
|
26
|
+
p = argparse.ArgumentParser(prog="arabcheck", description="ArabCheck โ ุชูุธูู ููุญุต ุงููุตูุต ุงูุนุฑุจูุฉ.")
|
|
27
|
+
p.add_argument("text", nargs="?", help="ุงููุต")
|
|
28
|
+
p.add_argument("-f", "--file", type=Path, help="ูุฑุงุกุฉ ู
ู ู
ูู")
|
|
29
|
+
p.add_argument("-c", "--clean", action="store_true")
|
|
30
|
+
p.add_argument("-n", "--normalize", action="store_true")
|
|
31
|
+
p.add_argument("-a", "--audit", action="store_true")
|
|
32
|
+
p.add_argument("-j", "--json", action="store_true")
|
|
33
|
+
p.add_argument("-q", "--quiet", action="store_true")
|
|
34
|
+
p.add_argument("-V", "--version", action="version", version=f"%(prog)s {__version__}")
|
|
35
|
+
return p
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def main(argv=None) -> int:
|
|
39
|
+
parser = build_parser()
|
|
40
|
+
args = parser.parse_args(argv)
|
|
41
|
+
text = read_input(args, parser)
|
|
42
|
+
checker = ArabCheck()
|
|
43
|
+
result = checker.process(text, clean=args.clean, normalize=args.normalize, audit=args.audit)
|
|
44
|
+
if args.json:
|
|
45
|
+
payload = {**result, "meta": {
|
|
46
|
+
"cleaned": args.clean, "normalized": args.normalize,
|
|
47
|
+
"audited": args.audit, "version": __version__,
|
|
48
|
+
}}
|
|
49
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
50
|
+
else:
|
|
51
|
+
if not args.quiet:
|
|
52
|
+
print(result["result"])
|
|
53
|
+
for issue in result["issues"]:
|
|
54
|
+
print(f"โ ๏ธ {issue['message']}", file=sys.stderr)
|
|
55
|
+
return 1 if result["issues"] else 0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
sys.exit(main())
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""ุงูููุงุฉ ุงูุฑุฆูุณูุฉ ูู ArabCheck."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from .patterns import Patterns
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ArabCheck:
|
|
7
|
+
def __init__(self) -> None:
|
|
8
|
+
self.patterns = Patterns()
|
|
9
|
+
|
|
10
|
+
def strip_tashkeel(self, text: str) -> str:
|
|
11
|
+
return self.patterns.TASHKEEL.sub("", text)
|
|
12
|
+
|
|
13
|
+
def strip_tatweel(self, text: str) -> str:
|
|
14
|
+
return self.patterns.TATWEEL.sub("", text)
|
|
15
|
+
|
|
16
|
+
def clean_text(self, text: str) -> str:
|
|
17
|
+
text = self.strip_tashkeel(text)
|
|
18
|
+
text = self.strip_tatweel(text)
|
|
19
|
+
return self.patterns.WHITESPACE.sub(" ", text).strip()
|
|
20
|
+
|
|
21
|
+
def normalize(self, text: str, *, taa_marbuta: bool = False) -> str:
|
|
22
|
+
text = self.patterns.ALIF_VARIANTS.sub("ุง", text)
|
|
23
|
+
text = self.patterns.YAA_VARIANTS.sub("ู", text)
|
|
24
|
+
text = self.patterns.HAMZA_WAW.sub("ู", text)
|
|
25
|
+
text = self.patterns.HAMZA_YAA.sub("ู", text)
|
|
26
|
+
if taa_marbuta:
|
|
27
|
+
text = self.patterns.TAA_MARBUTA.sub("ู", text)
|
|
28
|
+
return text
|
|
29
|
+
|
|
30
|
+
def audit(self, text: str) -> list:
|
|
31
|
+
issues = []
|
|
32
|
+
for i, word in enumerate(text.split(), start=1):
|
|
33
|
+
if self.patterns.HAMZAT_QAT.match(word):
|
|
34
|
+
issues.append({
|
|
35
|
+
"type": "hamzat_qat",
|
|
36
|
+
"word": word,
|
|
37
|
+
"position": i,
|
|
38
|
+
"message": f"ุงุญุชู
ุงู ุฎุทุฃ: '{word}' ุชุจุฏุฃ ุจู 'ุงู' + ูู
ุฒุฉ ูุทุน.",
|
|
39
|
+
})
|
|
40
|
+
return issues
|
|
41
|
+
|
|
42
|
+
def process(self, text, *, clean=False, normalize=False, audit=False):
|
|
43
|
+
issues = self.audit(text) if audit else []
|
|
44
|
+
result = text
|
|
45
|
+
if normalize:
|
|
46
|
+
result = self.normalize(result)
|
|
47
|
+
if clean:
|
|
48
|
+
result = self.clean_text(result)
|
|
49
|
+
return {"input": text, "result": result, "issues": issues}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""ุฃูู
ุงุท regex ุงูู
ุฌู
ูุนุฉ ู
ุณุจูุงู."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Patterns:
|
|
8
|
+
"""ุฃูู
ุงุท regex ูุฃุฏุงุก ุฃูุถู (compiled once)."""
|
|
9
|
+
|
|
10
|
+
# ุงูุชุดููู: ุญุฑูุงุช + ุนูุงู
ุงุช ูุฑุขููุฉ + ุฃูู ุฎูุฌุฑูุฉ
|
|
11
|
+
TASHKEEL = re.compile(
|
|
12
|
+
"[\u0610-\u061A\u064B-\u065F\u0670"
|
|
13
|
+
"\u06D6-\u06DC\u06DF-\u06E8\u06EA-\u06ED]"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
TATWEEL = re.compile("\u0640")
|
|
17
|
+
WHITESPACE = re.compile(r"\s+")
|
|
18
|
+
|
|
19
|
+
# ูู
ุฒุฉ ูุทุน ุจุนุฏ "ุงู" ุงูุชุนุฑูู
|
|
20
|
+
HAMZAT_QAT = re.compile(r"^ุงู[ุฃุฅุข]")
|
|
21
|
+
|
|
22
|
+
# ููุชูุญูุฏ โ ูู ูุงุญุฏ ู
ููุตู ุนุดุงู ูุจูู ูุงุถุญ
|
|
23
|
+
ALIF_VARIANTS = re.compile(r"[ุฅุฃุขูฑ]")
|
|
24
|
+
YAA_VARIANTS = re.compile(r"[ูู]")
|
|
25
|
+
TAA_MARBUTA = re.compile(r"ุฉ")
|
|
26
|
+
HAMZA_WAW = re.compile(r"ุค")
|
|
27
|
+
HAMZA_YAA = re.compile(r"ุฆ")
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: arabcheck
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight toolkit and CLI for cleaning, normalizing, and auditing Arabic text.
|
|
5
|
+
Author-email: Mohamed Kamal Salih Mahmod <102423366+MOHAMEDKAMALSALLIH@users.noreply.github.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/MOHAMEDKAMALSALLIH/arabcheck
|
|
8
|
+
Project-URL: Repository, https://github.com/MOHAMEDKAMALSALLIH/arabcheck
|
|
9
|
+
Project-URL: Issues, https://github.com/MOHAMEDKAMALSALLIH/arabcheck/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/MOHAMEDKAMALSALLIH/arabcheck/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Releases, https://github.com/MOHAMEDKAMALSALLIH/arabcheck/releases
|
|
12
|
+
Keywords: arabic,nlp,text-cleaning,tashkeel
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Natural Language :: Arabic
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# ArabCheck ๐
|
|
25
|
+
|
|
26
|
+
> A lightweight, open-source toolkit and CLI for cleaning, normalizing, and auditing Arabic text for AI and NLP workflows.
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+

|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Why ArabCheck?
|
|
35
|
+
|
|
36
|
+
Arabic text data often contains noise that breaks NLP pipelines:
|
|
37
|
+
|
|
38
|
+
- **Unicode variants** โ `ุฃ` / `ุฅ` / `ุข` / `ุง` / `ูฑ` all represent alif
|
|
39
|
+
- **Diacritics (Tashkeel)** โ fatha, damma, shadda, tanween
|
|
40
|
+
- **Tatweel (Kashida)** โ decorative stretching characters `ููููู`
|
|
41
|
+
- **Quranic marks** and extra whitespace
|
|
42
|
+
|
|
43
|
+
ArabCheck makes cleaning and auditing this data a one-liner โ with full transparency and configurable operations.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- ๐ **Tashkeel removal** โ Harakat + Quranic marks
|
|
50
|
+
- ๐ค **Character normalization** โ Alif, Yaa, Hamza, Taa Marbuta
|
|
51
|
+
- ใฐ๏ธ **Tatweel removal** โ Kashida stretching characters
|
|
52
|
+
- ๐งน **Text cleaning** โ Whitespace normalization
|
|
53
|
+
- ๐ **Grammar audit** โ Detect common hamzat qat/wasl errors
|
|
54
|
+
- ๐ **File + stdin support**
|
|
55
|
+
- ๐ค **JSON output** for CI/CD pipelines
|
|
56
|
+
- ๐งฉ **Extensible** โ easy to add new rules
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://github.com/MOHAMEDKAMALSALLIH/arabcheck.git
|
|
64
|
+
cd arabcheck
|
|
65
|
+
pip install -e .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Requirements: Python 3.8+ โ no external dependencies.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
Quick Start
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
arabcheck "ุงููููุตูู ุงูุนูุฑูุจูููู ูููุชููุฌูุฑูุจูุฉ" --clean
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Input:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
ุงููููุตูู ุงูุนูุฑูุจูููู ูููุชููุฌูุฑูุจูุฉ
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Output:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
ุงููุต ุงูุนุฑุจู ููุชุฌุฑุจุฉ
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
Usage Examples
|
|
93
|
+
|
|
94
|
+
1. Clean text
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
arabcheck "ุงูุนูุฑูุจููููุฉู ููู ููุบูุฉู ุฌูู
ููููุฉู" --clean
|
|
98
|
+
# โ ุงูุนุฑุจูุฉ ูุบุฉ ุฌู
ููุฉ
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
2. Normalize characters
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
arabcheck "ุฃุญู
ุฏ ุฅุจุฑุงููู
ุขู
ู" --normalize
|
|
105
|
+
# โ ุงุญู
ุฏ ุงุจุฑุงููู
ุงู
ู
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
โ ๏ธ Warning: Normalization loses linguistic information. Use it for search, indexing, or NLP pipelines only.
|
|
109
|
+
|
|
110
|
+
3. Audit text
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
arabcheck "ุงูุฃู
ุฑ ุจุงูุฃู
ุฑ" --audit
|
|
114
|
+
# โ ๏ธ ุงุญุชู
ุงู ุฎุทุฃ: 'ุงูุฃู
ุฑ' ุชุจุฏุฃ ุจู 'ุงู' + ูู
ุฒุฉ ูุทุน.
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
4. JSON output (for automation)
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
arabcheck "ุงููููุตูู" --clean --json
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"input": "ุงููููุตูู",
|
|
126
|
+
"result": "ุงููุต",
|
|
127
|
+
"issues": [],
|
|
128
|
+
"meta": {
|
|
129
|
+
"cleaned": true,
|
|
130
|
+
"normalized": false,
|
|
131
|
+
"audited": false,
|
|
132
|
+
"version": "0.1.0"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
5. Read from file
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
arabcheck --file dataset.txt --clean
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
6. From stdin
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
cat article.txt | arabcheck --clean
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
CLI Reference
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
usage: arabcheck [-h] [-f FILE] [-c] [-n] [-a] [-j] [-q] [-V] [text]
|
|
155
|
+
|
|
156
|
+
positional arguments:
|
|
157
|
+
text Text to process
|
|
158
|
+
|
|
159
|
+
options:
|
|
160
|
+
-h, --help Show help
|
|
161
|
+
-f, --file FILE Read text from file
|
|
162
|
+
-c, --clean Remove tashkeel, tatweel and extra whitespace
|
|
163
|
+
-n, --normalize Normalize letters (alif, yaa, etc.)
|
|
164
|
+
-a, --audit Audit common spelling issues
|
|
165
|
+
-j, --json Output as JSON
|
|
166
|
+
-q, --quiet Suppress text output
|
|
167
|
+
-V, --version Show version
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Exit Codes
|
|
171
|
+
|
|
172
|
+
Code Meaning
|
|
173
|
+
0 Success, no issues
|
|
174
|
+
1 Issues found (with --audit)
|
|
175
|
+
2 Input error
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
Use as a Library
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from arabcheck import ArabCheck
|
|
183
|
+
|
|
184
|
+
checker = ArabCheck()
|
|
185
|
+
|
|
186
|
+
# Clean
|
|
187
|
+
text = checker.clean_text("ุงููููุตูู ุงูุนูุฑูุจูููู ููู")
|
|
188
|
+
print(text) # โ ุงููุต ุงูุนุฑุจู
|
|
189
|
+
|
|
190
|
+
# Normalize
|
|
191
|
+
print(checker.normalize("ุฃุญู
ุฏ ุฅุจุฑุงููู
"))
|
|
192
|
+
# โ ุงุญู
ุฏ ุงุจุฑุงููู
|
|
193
|
+
|
|
194
|
+
# Audit
|
|
195
|
+
issues = checker.audit("ุงูุฃู
ุฑ ุจุงูุฃู
ุฑ")
|
|
196
|
+
for issue in issues:
|
|
197
|
+
print(issue["message"])
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
Testing
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
pip install -e ".[dev]"
|
|
206
|
+
pytest
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
Roadmap
|
|
212
|
+
|
|
213
|
+
โ Tashkeel & Tatweel removal
|
|
214
|
+
โ Character normalization
|
|
215
|
+
โ File + stdin support
|
|
216
|
+
โ JSON output
|
|
217
|
+
โ Exit codes for CI/CD
|
|
218
|
+
โ Grammar audit (hamzat qat/wasl)
|
|
219
|
+
โ Extended audit rules
|
|
220
|
+
โ Dataset loading (CSV, JSONL)
|
|
221
|
+
โ Duplicate detection
|
|
222
|
+
โ Text quality statistics
|
|
223
|
+
โ Publish on PyPI
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
Contributing
|
|
228
|
+
|
|
229
|
+
Contributions, issues, and feature requests are welcome! See CONTRIBUTING.md for guidelines.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
Releases
|
|
234
|
+
|
|
235
|
+
See Releases for version history.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
License
|
|
240
|
+
|
|
241
|
+
MIT โ see LICENSE for details.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
<p align="center">
|
|
246
|
+
Made with โค๏ธ for the Arabic NLP community
|
|
247
|
+
</p>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/arabcheck/__init__.py
|
|
5
|
+
src/arabcheck/__main__.py
|
|
6
|
+
src/arabcheck/cli.py
|
|
7
|
+
src/arabcheck/core.py
|
|
8
|
+
src/arabcheck/patterns.py
|
|
9
|
+
src/arabcheck.egg-info/PKG-INFO
|
|
10
|
+
src/arabcheck.egg-info/SOURCES.txt
|
|
11
|
+
src/arabcheck.egg-info/dependency_links.txt
|
|
12
|
+
src/arabcheck.egg-info/entry_points.txt
|
|
13
|
+
src/arabcheck.egg-info/requires.txt
|
|
14
|
+
src/arabcheck.egg-info/top_level.txt
|
|
15
|
+
tests/test_cli.py
|
|
16
|
+
tests/test_core.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
arabcheck
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Tests for the ArabCheck CLI."""
|
|
2
|
+
import json
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def run_cli(*args, input_text=None):
|
|
11
|
+
"""Helper to run the CLI and capture output."""
|
|
12
|
+
return subprocess.run(
|
|
13
|
+
[sys.executable, "-m", "arabcheck", *args],
|
|
14
|
+
capture_output=True,
|
|
15
|
+
text=True,
|
|
16
|
+
input=input_text,
|
|
17
|
+
encoding="utf-8",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# ---------- Version ----------
|
|
22
|
+
def test_cli_version():
|
|
23
|
+
result = run_cli("--version")
|
|
24
|
+
assert result.returncode == 0
|
|
25
|
+
assert "arabcheck" in result.stdout.lower()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# ---------- Clean ----------
|
|
29
|
+
def test_cli_clean():
|
|
30
|
+
result = run_cli("ุงููููุตูู ุงูุนูุฑูุจูููู", "--clean")
|
|
31
|
+
assert result.returncode == 0
|
|
32
|
+
assert "ุงููุต ุงูุนุฑุจู" in result.stdout
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_cli_clean_with_tatweel():
|
|
36
|
+
result = run_cli("ู
ููุฑุญุจููุง", "--clean")
|
|
37
|
+
assert result.returncode == 0
|
|
38
|
+
assert "ู
ุฑุญุจุง" in result.stdout
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ---------- Normalize ----------
|
|
42
|
+
def test_cli_normalize():
|
|
43
|
+
result = run_cli("ุฃุญู
ุฏ ุฅุจุฑุงููู
", "--normalize")
|
|
44
|
+
assert result.returncode == 0
|
|
45
|
+
assert "ุงุญู
ุฏ ุงุจุฑุงููู
" in result.stdout
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# ---------- Audit & exit codes ----------
|
|
49
|
+
def test_cli_audit_clean_returns_zero():
|
|
50
|
+
result = run_cli("ุงูุณูุงู
ุนูููู
", "--audit")
|
|
51
|
+
assert result.returncode == 0
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_cli_audit_issues_returns_one():
|
|
55
|
+
result = run_cli("ุงูุฃู
ุฑ", "--audit")
|
|
56
|
+
assert result.returncode == 1
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# ---------- JSON ----------
|
|
60
|
+
def test_cli_json_output():
|
|
61
|
+
result = run_cli("ุงููููุตูู", "--clean", "--json")
|
|
62
|
+
assert result.returncode == 0
|
|
63
|
+
data = json.loads(result.stdout)
|
|
64
|
+
assert data["input"] == "ุงููููุตูู"
|
|
65
|
+
assert data["result"] == "ุงููุต"
|
|
66
|
+
assert "issues" in data
|
|
67
|
+
assert "meta" in data
|
|
68
|
+
assert data["meta"]["cleaned"] is True
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_cli_json_with_audit():
|
|
72
|
+
result = run_cli("ุงูุฃู
ุฑ", "--audit", "--json")
|
|
73
|
+
data = json.loads(result.stdout)
|
|
74
|
+
assert len(data["issues"]) == 1
|
|
75
|
+
assert data["issues"][0]["type"] == "hamzat_qat"
|
|
76
|
+
assert result.returncode == 1
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# ---------- Quiet ----------
|
|
80
|
+
def test_cli_quiet():
|
|
81
|
+
result = run_cli("ุงููููุตูู", "--clean", "--quiet")
|
|
82
|
+
assert result.returncode == 0
|
|
83
|
+
assert "ุงููุต" not in result.stdout
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# ---------- File input ----------
|
|
87
|
+
def test_cli_file_input(tmp_path):
|
|
88
|
+
f = tmp_path / "input.txt"
|
|
89
|
+
f.write_text("ุงููููุตูู ุงูุนูุฑูุจูููู", encoding="utf-8")
|
|
90
|
+
result = run_cli("--file", str(f), "--clean")
|
|
91
|
+
assert result.returncode == 0
|
|
92
|
+
assert "ุงููุต ุงูุนุฑุจู" in result.stdout
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_cli_missing_file_returns_two():
|
|
96
|
+
result = run_cli("--file", "/nonexistent/file.txt", "--clean")
|
|
97
|
+
assert result.returncode == 2
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# ---------- stdin ----------
|
|
101
|
+
def test_cli_stdin():
|
|
102
|
+
result = run_cli("--clean", input_text="ุงููููุตูู")
|
|
103
|
+
assert result.returncode == 0
|
|
104
|
+
assert "ุงููุต" in result.stdout
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from arabcheck import ArabCheck
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@pytest.fixture
|
|
6
|
+
def checker():
|
|
7
|
+
return ArabCheck()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_strip_tashkeel(checker):
|
|
11
|
+
assert checker.strip_tashkeel("ุงููููุตูู") == "ุงููุต"
|
|
12
|
+
|
|
13
|
+
def test_strip_tatweel(checker):
|
|
14
|
+
assert checker.strip_tatweel("ุนูููุฑุจู") == "ุนุฑุจู"
|
|
15
|
+
|
|
16
|
+
def test_clean_text(checker):
|
|
17
|
+
assert checker.clean_text("ุงูุนูุฑูุจููููุฉู ููู ููุบูุฉู") == "ุงูุนุฑุจูุฉ ูุบุฉ"
|
|
18
|
+
|
|
19
|
+
def test_normalize_alif(checker):
|
|
20
|
+
assert checker.normalize("ุฃุญู
ุฏ ุฅุจุฑุงููู
ุขู
ู") == "ุงุญู
ุฏ ุงุจุฑุงููู
ุงู
ู"
|
|
21
|
+
|
|
22
|
+
def test_normalize_yaa(checker):
|
|
23
|
+
assert checker.normalize("ู
ุตุทูู") == "ู
ุตุทูู"
|
|
24
|
+
|
|
25
|
+
def test_normalize_taa_marbuta_default(checker):
|
|
26
|
+
assert "ุฉ" in checker.normalize("ู
ุฏุฑุณุฉ")
|
|
27
|
+
|
|
28
|
+
def test_normalize_taa_marbuta_enabled(checker):
|
|
29
|
+
assert checker.normalize("ู
ุฏุฑุณุฉ", taa_marbuta=True) == "ู
ุฏุฑุณู"
|
|
30
|
+
|
|
31
|
+
def test_audit_detects_hamzat_qat(checker):
|
|
32
|
+
issues = checker.audit("ุงูุฃู
ุฑ")
|
|
33
|
+
assert len(issues) == 1
|
|
34
|
+
assert issues[0]["type"] == "hamzat_qat"
|
|
35
|
+
|
|
36
|
+
def test_audit_clean_text(checker):
|
|
37
|
+
assert checker.audit("ุงูุณูุงู
ุนูููู
") == []
|
|
38
|
+
|
|
39
|
+
def test_process_combined(checker):
|
|
40
|
+
result = checker.process("ุงูุฃูู
ูุฑู ููู ุงูุฃููููู", clean=True, audit=True)
|
|
41
|
+
assert result["result"] == "ุงูุฃู
ุฑ ุงูุฃูู"
|
|
42
|
+
assert len(result["issues"]) == 2
|