forked from FooSoft/yomichan
-
Notifications
You must be signed in to change notification settings - Fork 258
Expand file tree
/
Copy patharabic-text-preprocessors.js
More file actions
126 lines (110 loc) · 4.39 KB
/
Copy patharabic-text-preprocessors.js
File metadata and controls
126 lines (110 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
* Copyright (C) 2024-2026 Yomitan Authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Generates all possible combinations of replacing each occurrence of a
* pattern with each of the options provided in replacements.
*
* For a pattern that matches `n` times, and a list of `m` replacements, this
* function returns `m^n` strings representing every possible combination of replacements.
*
* Note: This function should not be used for large values of n and m, due to its inherent
* exponential growth.
* @param {string} str
* @param {string|RegExp} pattern
* @param {string[]} replacements
* @returns {string[]}
*/
function generateReplacementCombinations(str, pattern, replacements) {
const regex = pattern instanceof RegExp ? pattern : new RegExp(pattern, 'g');
const matches = [...str.matchAll(regex)];
const n = matches.length;
const m = replacements.length; // number of choices per match
const total = m ** n; // m^n combinations
const results = [];
for (let combination = 0; combination < total; combination++) {
// Treat `combination` as a base-m number with n digits.
// Starting from the least significant digit, position 0, until the most significant digit,
// position n-1, we loop through each digit of `combination`. Each position i is a digit
// between 0 and m-1, representing which of the m replacement choices to substitute the ith
// occurrence of `pattern` with
let current = combination;
const result = str.replaceAll(regex, (_) => {
// Pick replacement choice using the value of the current least significant digit
const choiceIndex = current % m;
// Pop the least significant digit
current = Math.floor(current / m);
return replacements[choiceIndex];
});
results.push(result);
}
return results;
}
const optionalDiacritics = [
'\u0618', // Small Fatha
'\u0619', // Small Damma
'\u061A', // Small Kasra
'\u064B', // Fathatan
'\u064C', // Dammatan
'\u064D', // Kasratan
'\u064E', // Fatha
'\u064F', // Damma
'\u0650', // Kasra
'\u0651', // Shadda
'\u0652', // Sukun
'\u0653', // Maddah
'\u0654', // Hamza Above
'\u0655', // Hamza Below
'\u0656', // Subscript Alef
'\u0670', // Dagger Alef
];
const diacriticsRegex = new RegExp(`[${optionalDiacritics.join('')}]`, 'g');
/** @type {import('language').TextProcessor} */
export const removeArabicScriptDiacritics = {
name: 'Remove diacritics',
description: 'وَلَدَ → ولد',
process: (text) => [text, text.replace(diacriticsRegex, '')],
};
/** @type {import('language').TextProcessor} */
export const removeTatweel = {
name: 'Remove tatweel characters',
description: 'لـكن → لكن',
process: (text) => [text, text.replaceAll('ـ', '')],
};
/** @type {import('language').TextProcessor} */
export const normalizeUnicode = {
name: 'Normalize unicode',
description: 'ﻴ → ي',
process: (text) => [text, text.normalize('NFKC')],
};
/** @type {import('language').TextProcessor} */
export const substituteAlif = {
name: 'Substitutes plain alifs with its variations (alif with hamza, alif with madd)',
description: 'اكبر → أكبر',
process: (text) => generateReplacementCombinations(text, 'ا', ['ا', 'أ', 'إ', 'آ']),
};
/** @type {import('language').TextProcessor} */
export const convertAlifMaqsuraToYaa = {
name: 'Convert Alif Maqsura to Yaa',
description: 'فى → في',
process: (text) => [text, text.replace(/ى$/, 'ي')],
};
/** @type {import('language').TextProcessor} */
export const convertHaToTaMarbuta = {
name: 'Convert final Ha to Ta Marbuta',
description: 'لغه → لغة',
process: (text) => [text, text.replace(/ه$/, 'ة')],
};