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.
@@ -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.
@@ -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
+ ![Python](https://img.shields.io/badge/python-3.8%2B-blue)
29
+ ![License](https://img.shields.io/badge/license-MIT-green)
30
+ ![Status](https://img.shields.io/badge/status-alpha-orange)
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
+ ![Python](https://img.shields.io/badge/python-3.8%2B-blue)
6
+ ![License](https://img.shields.io/badge/license-MIT-green)
7
+ ![Status](https://img.shields.io/badge/status-alpha-orange)
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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,5 @@
1
+ """ArabCheck โ€” Lightweight Arabic text toolkit."""
2
+ from .core import ArabCheck
3
+
4
+ __version__ = "0.2.0"
5
+ __all__ = ["ArabCheck", "__version__"]
@@ -0,0 +1,5 @@
1
+ import sys
2
+ from .cli import main
3
+
4
+ if __name__ == "__main__":
5
+ sys.exit(main())
@@ -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
+ ![Python](https://img.shields.io/badge/python-3.8%2B-blue)
29
+ ![License](https://img.shields.io/badge/license-MIT-green)
30
+ ![Status](https://img.shields.io/badge/status-alpha-orange)
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,2 @@
1
+ [console_scripts]
2
+ arabcheck = arabcheck.cli:main
@@ -0,0 +1,3 @@
1
+
2
+ [dev]
3
+ pytest>=7
@@ -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