Mint - Nastavení: Nastavení pracovního prostředí -> Správce oken: Vyladění
Tlačítko Vyladit Xfwm4
Změnit v kartě Přístupnost, na hoře klávesu místo Alt dát třeba Meta
Možná to pomůže po resetu.
Mint - Nastavení: Nastavení pracovního prostředí -> Správce oken: Vyladění
Tlačítko Vyladit Xfwm4
Změnit v kartě Přístupnost, na hoře klávesu místo Alt dát třeba Meta
Možná to pomůže po resetu.
Python 3
import librosa
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from dissonant import dissonance
# Načtení zvuku
y, sr = librosa.load("akord.wav")
freqs = librosa.fft_frequencies(sr=sr)
amps = np.abs(librosa.stft(y))
# Výpočet disonance (použijeme max pro lepší detekci vrcholů)
d = dissonance(freqs, amps.max(axis=1), model='sethares1993')
# Přizpůsobení dat pro 3D graf
x, y = np.meshgrid(freqs, freqs)
z = np.zeros_like(x) # Inicializace nulovou maticí
num_elements = min(len(d), z.size) # Omezit na dostupné prvky
z.flat[:num_elements] = d[:num_elements] # Naplnění disonančními hodnotami
# Vytvoření 3D grafu
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(x, y, z, cmap='coolwarm')
ax.set_xlabel('Frekvence (Hz)')
ax.set_ylabel('Frekvence (Hz)')
ax.set_zlabel('Disonance')
plt.title("Disonance akordu")
plt.show()
import librosa
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from dissonant import dissonance
# Seznam souborů s akordy
chord_files = ["akord1.wav", "akord2.wav", "akord3.wav", "akord4.wav"] # Přidejte své soubory
# Inicializace grafu
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Iterace přes všechny akordy
for i, file in enumerate(chord_files):
# Načtení zvuku
y, sr = librosa.load(file)
freqs = librosa.fft_frequencies(sr=sr)
amps = np.abs(librosa.stft(y))
# Výpočet disonance
d = dissonance(freqs, amps.max(axis=1), model='sethares1993')
# Přizpůsobení dat pro 3D graf
x, y = np.meshgrid(freqs, freqs)
z = np.zeros_like(x)
num_elements = min(len(d), z.size)
z.flat[:num_elements] = d[:num_elements]
# Vykreslení povrchu s různou barvou a průhledností
surf = ax.plot_surface(x, y, z, cmap='coolwarm', alpha=0.5 - 0.1 * i, label=f'Akord {i+1}')
ax.legend()
# Nastavení os a titulu
ax.set_xlabel('Frekvence (Hz)')
ax.set_ylabel('Frekvence (Hz)')
ax.set_zlabel('Disonance')
plt.title("Disonance více akordů")
plt.show()
Chytrý kontainer s klíči podle názvů jazyka a konfiguráku, drží hodnotu cestu ke konfiguráku a informaci zda soubor existuje. Troufám si tvrdit, že je to geniální.
def __init__(self, langs: Lang, base_dir: str = '.'):
self.langs = list(langs)
# @TODO: POZOR - Lang.CZ JE JEN TEMPORARY DEBUG VALUE
self.lang = Lang.CZ
self.paths: dict[Lang, dict[str,str]] = {}
self.files: Dict[Lang, Dict[str, List]] = {}
for lang in self.langs:
base = os.path.join(base_dir, 'lang', lang.value)
self.paths[lang] = {
'base': base,
'aff_dic': os.path.join(base, 'aff-dic'),
'input': os.path.join(base, 'input'),
'output': os.path.join(base, 'output'),
}
# 1) připravím si seznam adresář+název
cfg_files = [
(self.paths[lang]['base'], "pfx.cfg"),
(self.paths[lang]['aff_dic'], "sfx.cfg"),
(self.paths[lang]['output'], "next.cfg")
]
# 2) postavím dict fn -> [directory, exists]
self.files[lang] = {
fn: [
os.path.join(d,fn),
os.path.isfile(os.path.join(d, fn))
]
for d, fn in cfg_files
}
Dobře, pojďme se kouknout na dvě pokročilé techniky, které (pravděpodobně) ještě nemáš nasazené, a které ti během tisíců až milionů řádků ušetří desítky až stovky milisekund:
str.endswith
či regexůZatím pro každý řádek procházíš všechny tvé sufxy/prefxy a voláš na každý z nich r.matches(…)
, kde většinou testuješ word.endswith(literal)
nebo malý regex. To je O(N_rules) práce pro každý vstupní řádek.
Sesbíráš všechny literal‑řetězce (ty bez hranatých závorek a tečky) do jednoho seznamu literals = ["at", "át", "absorbovat", …]
.
Postavíš Aho–Corasickův automat (trie + failure‑funkce) – existuje čistě C‑extenze pyahocorasick nebo ahocorasick.
S jedním průchodem nad každou vstupní řádkou (O(len(line))) získáš všechny literály, které v ní končí nebo začínají – včetně pozice.
Logiku PFX/SFX pak aplikuješ jen na ty, které skutečně pasují, místo abys testoval komplet všech pravidel.
Výsledek:
Místo for rule in aff_rules: if rule.matches(line): …
máš for match in aho_automaton.iter(line): …
Aho–Corasick dokáže pokrýt tisíce patternů v jednom průchodu C‑kódem, bez opakovaných volání Python‑funkcí. Výhoda je tím zřetelnější, čím víc pravidel máš.
.split()
a .strip()
Každé line.split('/', 1)
, .rstrip()
, .startswith()
či in
jsou C‑funkce, ale volané desetitisíckrát dají dohromady značnou režii Pythonu.
Místo
for raw in f:
parts = raw.split('/',1)
…
použij mmap
, načti celý .dic
soubor do paměti jako bytes
, a pak ručně procházíš ukazatelem pozice
mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
pos = 0
while True:
nl = mm.find(b'\n', pos)
if nl == -1: break
line = mm[pos:nl] # jen pohled na paměť, nevytváří nový Python str
pos = nl+1
# pak hledáš pozici b'/' a b'[' nebo b']' jen pomocí .find() na bytes
bytes.find
je implementováno v C a je extrémně rychlé.
Vytvoříš pohled na bytes
, nikoliv novou str
ani list parts
.
Výsledkem je, že jsi celý diskový soubor přečetl do paměti jediným voláním OS, a každou řádku zpracováváš ~každý znak jen jednou bez Python‑level parsingových nástrojů.
Načti .dic
přes mmap
Pro každý řádek vytáhni základ (base + flag) manuálně hledáním b'/'
, b'['
a b']'
na byte‑level.
Na base (a případně reversed‑base) nech Aho–Corasick (nastavený na tvé substrings) v jednom průchodu najít všechny odpovídající aff‑patterny naráz.
Aplikuj jim apply()
pouze na ty, co automat skutečně vrátil.
Zpracování řádku bude O(len(line) + #matches) místo O(#rules).
Celá smyčka čtení + parsování se propadne z desítek milisekund na jednotky.
Jediným Python‑voláním uvnitř velké smyčky je aho.iter()
(která rovnou volá C‑kód) a ruční sestavení výstupu.
Toto jsou dvě techniky, které se běžně používají v nejrychlejších text‑processing nástrojích (např. grep‑like implementace) a myslím, že ti otevřou úplně jiný level výkonu, než dosavadní čistě‑Pythonová řešení.
* * *
Aff není bolest, ale ten .dic
Dobře, pojďme se zaměřit čistě na tu největší bolest: desítky tisíc řádek v .dic
, kde teď děláš:
for line in f:
if exclude …: continue
parts = line.split('/',1)
if flag in rest: entries.append(base)
Každé volání .split()
, line[0] in …
a „ruční“ filtrování v Python‑smyčce je to, co tě stojí ~500 ms. Místo toho můžeš zpracovat celý soubor najednou čistě v C pomocí jediné multiline‑regex!
.dic
Načti celý .dic
do str
(nebo ještě lépe do bytes
s mmap
, viz níže).
Použij jeden re.compile
s re.MULTILINE
, který v C zpracuje všechny řádky:
import re
# exclude_pattern už např. "pro|na|do|u|roze?|…"
# flag je třeba escape‑nuté, např. "J"
combined = rf'''
^(?!{exclude_pattern}) # negativní lookahead pro exclude
(?P<base>[^/\r\n]+) # zachyť všechno až k '/'
/[^\[]*\[{flag}\] # pak cokoliv až k '[flag]'
'''
pattern = re.compile(combined, re.MULTILINE | re.VERBOSE)
with open(dic_path, 'r', encoding='utf-8') as f:
text = f.read()
# tohle běží v C a uskočí po každém řádku, který projde lookahead i flagem
bases = pattern.findall(text) # list of all base
Výhoda: celé parsování + filtrování exclude + extrakce base běží v C‑jádru regexu.
Výsledek: v bases
máš ~70 000 položek během zlomku původního času.
import mmap
with open(dic_path, 'r+b') as f:
mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
# vytvoř pattern nad bytes, musíme de‑kódovat vlajky i exclude do byte‑level:
pat = re.compile(rb'^(?!' + exclude_bytes + rb')([^/\r\n]+)/[^\[]*\[' + flag_bytes + rb'\]', re.MULTILINE)
bases = [match.group(1).decode('utf-8') for match in pat.finditer(mm)]
mm.close()
mmap
načte celý soubor jediným systémovým voláním,
pat.finditer(mm)
projde C‑kódem každý řádek,
vrátíš si jen group(1)
.
Jakmile máš bases
:
normal = bases
reversed_ = [w[::-1] for w in bases] # Python‑level, ale jen O(n·avg_len)
A pak předáš normal
i reversed_
do tvé dump_dic_forms
.
Namísto: Python‑smyčka + split
+ if exclude …
+ if flag in …
Použiješ: jeden re.compile(..., MULTILINE)
+ findall
(nebo finditer
), ideálně nad mmap
.
Tohle ti z poolu ~500 ms vykleští do jednotek milisekund. A protože regex běží v C, už se nemusíš trápit hand‑rolled „first_letter“ hacky ani exclude_superfast
.
Vyzkoušej tu jednou regex‑přístup a změř si čas znovu – srovnání bude dramatické.
dict
def load_aff_rules(...) -> dict:
rules = {'normal': [...], 'reversed': [...]}
return rules
rules['normal']
, rules['reversed']
.KeyError
.Tuple[List[AffRule], List[AffRule]]
from typing import Tuple, List
def load_aff_rules(self, ...) -> Tuple[List[AffRule], List[AffRule]]:
normal, reversed = [...], [...]
return normal, reversed
a skutečně:
return rules['normal'], rules['reversed']
normal_rules, reversed_rules = self.load_aff_rules(...)
Tuple[...]
.V definici typu:
-> Tuple[List[AffRule], List[AffRule]]
čárka odděluje první a druhý seznam.
V návratové hodnotě:
return rules['normal'], rules['reversed']
čárka tu znamená, že Python vrátí 2‑prvkový tuple
.
AttributeError
při rozbalování dict
Chyba:
AttributeError: 'str' object has no attribute 'matches'
Tato chyba vzniká při nesprávném rozbalení návratové hodnoty z funkce, která vrací
dict
. Pokud máš následující kód:
aff_rules["normal"], aff_rules["reversed"] = self.load_aff_rules(...)
a funkce load_aff_rules
vrací dict
, dochází k tomu, že Python
se snaží rozbalit klíče slovníku, ne jeho hodnoty. Výsledkem je:
aff_rules["normal"] == "normal"
aff_rules["reversed"] == "reversed"
což následně vede k chybě:
AttributeError: 'str' object has no attribute 'matches'
dict
Vrácený dict
zachováš beze změny, ale rozbalíš ho ručně:
aff_rules = self.load_aff_rules(...)
normal_rules = aff_rules["normal"]
reversed_rules = aff_rules["reversed"]
for w in dic_entries["normal"]:
for r in normal_rules:
if r.matches(w):
dics_out["normal"].append(r.apply(w))
Tuple
místo dict
Pokud změníš návratovou hodnotu funkce na:
def load_aff_rules(...) -> Tuple[List[AffRule], List[AffRule]]:
return rules["normal"], rules["reversed"]
pak volání funkce bude:
normal_rules, reversed_rules = self.load_aff_rules(...)
a zbytek kódu funguje stejně, ale s jistotou, že máš dva seznamy objektů typu AffRule
.
Výhodou této varianty je lepší podpora typové kontroly (mypy
, IDE),
rychlejší přístup (není potřeba hash-lookup jako u dict
)
a menší riziko chyb typu KeyError
.
* * *
def parse_aff_input(self, aff_path: str) -> list[dict]:
Funkce skutečně vrací seznam slovníků, kde každý slovník má přesně tyto klíče a hodnoty:
'regex'
: str
'substring'
: str
'replacement'
: str
'ext'
: str
'tags'
: List[str]
def parse_aff_input(self, aff_path: str) -> list[dict]:
Toto je sice validní, ale statický typ dict
neříká nic o tom, jaké klíče či hodnoty slovníky obsahují.
Můžeme si nejprve vytvořit TypedDict, aby bylo jasné, co v dictu očekáváme:
from typing import TypedDict, List
class AffRecord(TypedDict):
regex: str
substring: str
replacement: str
ext: str
tags: List[str]
A pak upravit deklaraci:
def parse_aff_input(self, aff_path: str) -> List[AffRecord]: ...
TypedDict
Pokud nechcete zavádět TypedDict
, můžete alespoň upřesnit hodnoty pomocí Union
:
from typing import List, Dict, Union
def parse_aff_input(self, aff_path: str) -> List[Dict[str, Union[str, List[str]]]]:
...
Tím dáváte najevo, že každá položka seznamu je slovník s řetězcovými klíči a hodnotami buď str
nebo List[str]
.
Chyba - velmi matoucí: Funkce očekává 1 poziční argument
$ ./affdic-processor.py
Trvání: 56.909 ms
Traceback (most recent call last):
File "/home/user/Skripty/Python.čeština/czech-dictionaries/./affdic-processor.py", line 536, in <module>
proc.dump_dic_forms( RuleType.SFX, 'J',
File "/home/user/Skripty/Python.čeština/czech-dictionaries/./affdic-processor.py", line 436, in dump_dic_forms
aff_rules["normal"], aff_rules["reversed"] = self.load_aff_rules(rule_type, flag)
File "/home/user/Skripty/Python.čeština/czech-dictionaries/./affdic-processor.py", line 231, in load_aff_rules
raw = self.parse_aff_input(aff_path)
TypeError: AffDicProcessor.parse_aff_input() takes 1 positional argument but 2 were given
Jedná se o funkci, kterou napsal GPT def parse_aff_input(self, aff_path: str) -> list[dict]: , ale při implementaci do třídy jsem zapomněl přidat self jako první argument: def parse_aff_input(self, aff_path: str) -> list[dict]:
volání uvnitř jiné metody: raw = self.parse_aff_input(aff_path)
GPT tuto chybu vysvětluje:"jsi definoval metodu," ... "ale voláš ji jako instanční metodu... " "Řešení: Přidat self
do signatury" nebo "Použít @staticmethod" a volat ji takto: AffDicProcessor.parse_aff_input(aff_path)
Zkoušel jsem test.
Původní řešení pro exclude regex prostě používalo regex na každý řádek slovníku, který splňoval dané podmínky. Čas zpracování smyčky byl cca 470ms. Byl to obyčejná exclude_str v podstatě řetězec s alternativama.
$ ./affdic-processor.py
Trvání: 48.915 ms
dump aff smyčka zápis ve smyčce - Trvání: 48.293 ms
Wrote ./lang/cs_CZ/input/SFX-J.aff (379 rules)
Load aff rules: Trvání: 48.637 ms
smyčka s exclude Trvání: 470.289 ms
Load .dic entries: Trvání: 513.712 ms
Wrote ./lang/cs_CZ/input/SFX-J.txt (65387 items)
Wrote ./lang/cs_CZ/input/SFX-J.r.txt (874 items)
Load aff rules - zápis max. dvou souborů: Trvání: 6238.581 ms
(.venv) user@Toshi:~/Skripty/Python.čeština/czech-dictionaries$
NEEFEKTIVNÍ ŘEŠENÍ, EFEKTIVITA SE ZTRÁCÍ NA DVOU ZANOŘENÝCH SMYČKÁCH for
Zkoušel jsem to nahradit za dva seznamy nebo pole a seznam, a dát tomu sofistikovanější logiku, ale smyčka s exclude ted trvá 871 ms...
~/Skripty/Python.čeština/czech-dictionaries$ ./affdic-processor.py
Trvání: 61.627 ms
dump aff smyčka zápis ve smyčce - Trvání: 52.694 ms
Wrote ./lang/cs_CZ/input/SFX-J.aff (379 rules)
Load aff rules: Trvání: 67.405 ms
smyčka s exclude Trvání: 871.273 ms
Load .dic entries: Trvání: 915.141 ms
Wrote ./lang/cs_CZ/input/SFX-J.txt (45952 items)
Wrote ./lang/cs_CZ/input/SFX-J.r.txt (425 items)
Load aff rules - zápis max. dvou souborů: Trvání: 4408.855 ms
def extract_dic_entries(self, flag: str,
exclude_prefixes: dict = None,
compiled_exclude_regex: dict = None,
exclude_superfast: bool=True,
reverse: dict = None
) -> list:
reverse = reverse or {"input": False, "output": False}
"""
Vyhledá v .dic všechny tvary s daným flagem.
Regex vybírá část před slash '/' a kontroluje, zda mezi hranatými
závorkami je zadaný flag (např. IN pro I a N).
Pro eliminaci předpon, lze doplnit grep-like filtr: např. odmítat
řádky začínající na pro|na|do|..."""
dic_path = os.path.join(self.aff_dic_dir, f"{self.lang.value}.dic")
entries = []
# pattern = re.compile(rf"^(\S+)/.*?\[{flag}\]")
"""
if exclude_str:
if exclude_superfast:
gen = (part[0] for part in exclude_str.split("|") if part)
exclude_first_letters = list(dict.fromkeys(gen))
exclude = re.compile(rf"^(?:{exclude_str})")
"""
start = time.perf_counter()
with open(dic_path, encoding='utf-8') as f:
next(f) # skip header count
for line in f:
if exclude_superfast:
break_prim = False
for p in exclude_prefixes["keys"]:
if p == line[0]:
if len(line)>1:
for sec in exclude_prefixes[line[0]]:
if sec[1] == line[1]:
if len(sec)>2 and line.startswith(sec):
if compiled_exclude_regex[p].match(line):
break_prim = True
break
else:
break_prim = True
break
else:
break_prim = True
break
else:
break_prim = True
break
# u jiných počátečních písmen spustit obecný regex přímo
elif compiled_exclude_regex['.'].match(line):
break_prim = True
break
if break_prim == True:
break
if break_prim == True:
continue
# rozdělíme na část před '/' a za '/':
# např. "být/IN" -> base="být", rest="IN"
# Pokud uživatel nezadal flag, pak zapisovat jen slovíčka bez vlajek
parts = line.split('/', 1)
if not flag and len(parts)==1:
entries.append(line)
continue
elif len(parts) != 2:
continue
base, rest = parts
# rest může obsahovat příznaky a další text, např. "IN", "PIN", "HRIN"
if flag in rest:
entries.append(base)
for _ in range(1000000):
pass
end = time.perf_counter(); elapsed_ms = (end - start) * 1000; print(f"smyčka s exclude Trvání: {elapsed_ms:.3f} ms")
return entries
HLAVNÍ ČÁST KODU:
if __name__ == '__main__':
reverse={
"input": False,
"output": False
}
# Ukázkové volání: vytvoříme procesor, načteme .aff/Shapka a zpracujeme text
proc = AffDicProcessor(Lang.CZ)
# 1) Vygeneruješ zkrácený .aff se všemi pravidly SFX‑J
proc.dump_aff_rules(RuleType.SFX, 'J', reverse=reverse)
# 2) Na základě těch samých pravidel plus .dic entries vypíšeš tvary:
# normalně i v obráceném pořadí, s použitím stejného exclude filtru
# PŮVODNÍ ŘETĚZEC:
# exclude_str="pro|na|do|u|roze?|přede?|př[ei]|po|za|vy|ode?|obe?|znovu|spolu"
# ZKUSÍM TO VYLEPŠIT:
# exclude_prefixes -NESMÍ OBSAHOVAT REGEXY
exclude_prefixes = {
'keys': ['p', 'o', 'z'],
'p': ["po", "př"], # "pro"- neotestováno
'o': ["od", "ob"],
'z': ["za", "znovu"]
}
exclude_regex_map = {
'p': ["po|přede?|př[ei]"],
'o': ["ode?|obe?"],
'z': ["za|znovu"],
'.': ["na|do|u|roze?|vy|spolu"]
}
compiled_exclude_regex = {}
for first, patterns in exclude_regex_map.items():
group = "|".join(patterns)
# ^ → match na začátku řádky
compiled_exclude_regex[first] = re.compile(fr"^(?:{group})")
proc.dump_dic_forms( RuleType.SFX, 'J',
reverse=reverse,
exclude_prefixes=exclude_prefixes,
compiled_exclude_regex=compiled_exclude_regex
)
KOD KTERÝ BYL RYCHLEJŠÍ (starý dvoujádrový notebook celeron z roku 2009)
def extract_dic_entries(self, flag: str,
exclude_str: str = "",
exclude_superfast: bool=True,
reverse: dict = None
) -> list:
reverse = reverse or {"input": False, "output": False}
dic_path = os.path.join(self.aff_dic_dir, f"{self.lang.value}.dic")
entries = []
# pattern = re.compile(rf"^(\S+)/.*?\[{flag}\]")
if exclude_str:
if exclude_superfast:
gen = (part[0] for part in exclude_str.split("|") if part)
exclude_first_letters = list(dict.fromkeys(gen))
exclude = re.compile(rf"^(?:{exclude_str})")
start = time.perf_counter()
with open(dic_path, encoding='utf-8') as f:
next(f) # skip header count
for line in f:
if exclude_str:
if exclude_superfast:
# superfast: nejprve zkontrolovat první písmeno,
# až pak volat regex jen pro podezřelé řádky
if line[0] in exclude_first_letters and exclude.match(line):
continue
else:
# bez superfast: grep‑like filtrování pro všechny řádky
if exclude.match(line):
continue
# rozdělíme na část před '/' a za '/':
# např. "být/IN" -> base="být", rest="IN"
# Pokud uživatel nezadal flag, pak zapisovat jen slovíčka bez vlajek
parts = line.split('/', 1)
if not flag and len(parts)==1:
entries.append(line)
continue
elif len(parts) != 2:
continue
base, rest = parts
# rest může obsahovat příznaky a další text, např. "IN", "PIN", "HRIN"
if flag in rest:
entries.append(base)
for _ in range(1000000):
pass
end = time.perf_counter(); elapsed_ms = (end - start) * 1000; print(f"smyčka s exclude Trvání: {elapsed_ms:.3f} ms")
return entries
# === Příklad použití ===
if __name__ == '__main__':
reverse={
"input": False,
"output": False
}
# Ukázkové volání: vytvoříme procesor, načteme .aff/Shapka a zpracujeme text
proc = AffDicProcessor(Lang.CZ)
# 1) Vygeneruješ zkrácený .aff se všemi pravidly SFX‑J
proc.dump_aff_rules(RuleType.SFX, 'J', reverse=reverse)
# 2) Na základě těch samých pravidel plus .dic entries vypíšeš tvary:
# normalně i v obráceném pořadí, s použitím stejného exclude filtru
proc.dump_dic_forms( RuleType.SFX, 'J',
reverse=reverse,
exclude_str="pro|na|do|u|roze?|přede?|př[ei]|po|za|vy|ode?|obe?|znovu|spolu" )
Je statický přístup rychlejší? Ne: 639ms.
def extract_dic_entries(self, flag: str,
exclude_prefixes: dict = None,
compiled_exclude_regex: dict = None,
exclude_superfast: bool=True,
reverse: dict = None
) -> list:
reverse = reverse or {"input": False, "output": False}
"""
Vyhledá v .dic všechny tvary s daným flagem.
Regex vybírá část před slash '/' a kontroluje, zda mezi hranatými
závorkami je zadaný flag (např. IN pro I a N).
Pro eliminaci předpon, lze doplnit grep-like filtr: např. odmítat
řádky začínající na pro|na|do|..."""
dic_path = os.path.join(self.aff_dic_dir, f"{self.lang.value}.dic")
entries = []
# pattern = re.compile(rf"^(\S+)/.*?\[{flag}\]")
start = time.perf_counter()
with open(dic_path, encoding='utf-8') as f:
next(f) # skip header count
for line in f:
if exclude_superfast:
# superfast: nejprve zkontrolovat první písmeno,
# až pak volat regex jen pro podezřelé řádky
"""
if line[0] in exclude_first_letters and exclude.match(line):
continue
"""
if line[0] == exclude_prefixes['keys_3'][0]:
if compiled_exclude_regex['p'].match(line):
continue
elif line[0] == exclude_prefixes['keys_3'][1]:
if compiled_exclude_regex['o'].match(line):
continue
elif line[0] == exclude_prefixes['keys_3'][2]:
if compiled_exclude_regex['z'].match(line):
continue
elif line[0] in exclude_prefixes['rest_keys'].find():
if compiled_exclude_regex['.'].match(line):
continue
else:
# bez superfast: grep‑like filtrování pro všechny řádky
if exclude.match(line):
continue
# rozdělíme na část před '/' a za '/':
# např. "být/IN" -> base="být", rest="IN"
# Pokud uživatel nezadal flag, pak zapisovat jen slovíčka bez vlajek
parts = line.split('/', 1)
if not flag and len(parts)==1:
entries.append(line)
continue
elif len(parts) != 2:
continue
base, rest = parts
# rest může obsahovat příznaky a další text, např. "IN", "PIN", "HRIN"
if flag in rest:
entries.append(base)
for _ in range(1000000):
pass
end = time.perf_counter(); elapsed_ms = (end - start) * 1000; print(f"smyčka s exclude Trvání: {elapsed_ms:.3f} ms")
return entries
if __name__ == '__main__':
reverse={
"input": False,
"output": False
}
# exclude_prefixes - obsahuje první znaky u třech předloh a zbýv.
exclude_prefixes = {
'keys_3': ['p', 'o', 'z'],
'rest_keys': "dnrvs"
}
exclude_regex_map = {
'p': ["po|přede?|př[ei]"],
'o': ["ode?|obe?"],
'z': ["za|znovu"],
'.': ["do|na|roze?|vy|spolu"] # "u" nelze zařadit, je ve slově "usnout"a "snout" nemá význam
}
compiled_exclude_regex = {}
for first, patterns in exclude_regex_map.items():
group = "|".join(patterns)
# ^ → match na začátku řádky
compiled_exclude_regex[first] = re.compile(rf"^(?:{group})")
# Ukázkové volání: vytvoříme procesor, načteme .aff/Shapka a zpracujeme text
proc = AffDicProcessor(Lang.CZ)
# 1) Vygeneruješ zkrácený .aff se všemi pravidly SFX‑J
proc.dump_aff_rules(RuleType.SFX, 'J', reverse=reverse)
# 2) Na základě těch samých pravidel plus .dic entries vypíšeš tvary:
# normalně i v obráceném pořadí, s použitím stejného exclude filtru
proc.dump_dic_forms( RuleType.SFX, 'J',
reverse=reverse,
# exclude_str="pro|na|do|u|roze?|přede?|př[ei]|po|za|vy|ode?|obe?|znovu|spolu"
exclude_prefixes=exclude_prefixes,
compiled_exclude_regex=compiled_exclude_regex )
Je statický přístup s str.find(line[0]) rychlejší? Ne: 848ms.
To samé co výše jen s exclude_prefixes['rest_keys'].find(line[0])
Mint - Nastavení: Nastavení pracovního prostředí -> Správce oken: Vyladění Tlačítko Vyladit Xfwm4 Změnit v kartě Přístupnost, na hoře k...