fix for snippets update
[wolnelektury.git] / scripts / fold_hunspell.py
1 #!/usr/bin/env python3
2 """
3 Tworzy wersję słownika hunspell bez polskich znaków dla PostgreSQL (szablon ispell).
4
5 Użycie:
6     fold_hunspell.py polish.dict polish.affix polish_ascii.dict polish_ascii.affix
7
8 Pliki wejściowe muszą być w UTF-8 (po iconv z ISO-8859-2).
9
10 Samo usunięcie znaków psuje warunki reguł z klasami negowanymi: np.
11 `SFX H ć ło [^ąeśź]ć` (wszystko poza ą, e, ś, ź przed ć) po zamianie
12 stałoby się `[^aesz]c` i przestało pasować do czasowników na -ać.
13 Dlatego litera zostaje w klasie negowanej tylko wtedy, gdy oryginał
14 wykluczał wszystkie litery, które się na nią składają; w przeciwnym
15 razie jest usuwana, a pusta klasa zamienia się w `.`. Reguły stają się
16 przez to nieco zbyt liberalne (nadmiarowe formy), ale żadna forma nie ginie.
17 """
18 import re
19 import sys
20 import unicodedata
21
22
23 def fold(text):
24     text = text.replace('ł', 'l').replace('Ł', 'L')
25     return ''.join(
26         c for c in unicodedata.normalize('NFKD', text)
27         if not unicodedata.combining(c)
28     )
29
30
31 LETTERS = 'aąbcćdeęfghijklłmnńoóprsśtuvwxyzźż'
32 GROUPS = {}
33 for letter in LETTERS:
34     GROUPS.setdefault(fold(letter), set()).add(letter)
35
36
37 def fold_negated_class(match):
38     excluded = set(match.group(1))
39     keep = []
40     for c in match.group(1):
41         folded = fold(c)
42         if GROUPS.get(folded, {c}) <= excluded and folded not in keep:
43             keep.append(folded)
44     return '[^' + ''.join(keep) + ']' if keep else '.'
45
46
47 def fold_affix_line(line):
48     parts = line.split()
49     if len(parts) >= 5 and parts[0] in ('SFX', 'PFX') and '[^' in parts[4]:
50         condition = re.sub(r'\[\^([^\]]*)\]', fold_negated_class, parts[4])
51         line = line.replace(parts[4], condition, 1)
52     if line.startswith('SET '):
53         return 'SET UTF-8\n'
54     return fold(line)
55
56
57 def main(dict_in, affix_in, dict_out, affix_out):
58     with open(dict_in, encoding='utf-8') as src, open(dict_out, 'w', encoding='utf-8') as dst:
59         dst.write(fold(src.read()))
60     with open(affix_in, encoding='utf-8') as src, open(affix_out, 'w', encoding='utf-8') as dst:
61         for line in src:
62             dst.write(fold_affix_line(line))
63
64
65 if __name__ == '__main__':
66     main(*sys.argv[1:5])