Skip to content

Instantly share code, notes, and snippets.

@alexeyev
Last active July 26, 2023 17:41
Show Gist options
  • Save alexeyev/532894d514701994363396fb07d6749b to your computer and use it in GitHub Desktop.
Save alexeyev/532894d514701994363396fb07d6749b to your computer and use it in GitHub Desktop.
Apertium-Kir-Based Tokenizer
# coding: utf-8
"""
Tokenization as it is done in Apertium; may not be blazing fast,
since a full-scale morphological analysis is carried out
"""
import apertium
import re
from typing import List, Tuple
from streamparser import LexicalUnit, reading_to_string
SPECIAL_CHARACTERS = list("/^$<>*{}\\@#+~")
REPLACEMENTS = ["shashchar", "capchar", "dollarchar", "lesschar", "morechar", "astchar",
"curlyleftchar", "curlyrightchar", "backslashchar", "atchar", "hashchar",
"pluschar", "tildechar"]
assert len(SPECIAL_CHARACTERS) == len(REPLACEMENTS)
spchar2code = {ch: co for ch, co in zip(SPECIAL_CHARACTERS, REPLACEMENTS)}
code2spchar = {co: ch for ch, co in zip(SPECIAL_CHARACTERS, REPLACEMENTS)}
class ApertiumSimpleTokenizer(object):
def __init__(self, lang="kir", already_installed=True):
"""
Loading the analyzer may take time
"""
if not already_installed:
apertium.installer.install_module(lang)
self.analyzer = apertium.Analyzer(lang)
def tokenize(self, text: str) -> List[str]:
for spc in spchar2code:
text = text.replace(spc, f" {spchar2code[spc]} ")
analysis: List[LexicalUnit] = self.analyzer.analyze(text)
decoded = [lu.wordform if lu.wordform not in code2spchar else code2spchar[lu.wordform] for lu in analysis]
return [w if len(w) == 1 else w.strip("\\") for w in decoded]
def span_tokenize(self, text: str) -> List[Tuple[int, int]]:
tokens, results, last_token = self.tokenize(text), [], 0
for token in tokens:
start_index_in_reduced = text[last_token:].find(token)
if start_index_in_reduced == -1:
raise Exception(
f"Token not found! \n'{token}' in '{text[last_token - 1:last_token + 10]}';\n "
f"tokens: {tokens}.")
start_index = start_index_in_reduced + last_token
results.append((start_index, start_index + len(token)))
last_token = start_index + len(token)
return results
if __name__ == "__main__":
from nltk import TreebankWordTokenizer
test_text = """Кыргызстанда ВИЧ/СПИД менен күрөшүүгө акча жетишпейт.
Бул тууралуу «24.kg» маалымат агентигине бул дарт менен күрөшүү Республикалык борборунун директору Улан Кадырбеков билдирди.
Анын маалыматында, 2003 — жылдан бери Глобалдуу фонд Кыргызстанга ВИЧ/СПИД менен күрөшүүгө 125 миллион доллар бөлгөн.
Бул каражат программанын алкагындагы иш чараларга жана дары-дармек сатып алууга жумшалат.
Улан Кадырбековдун айтымында, учурда 2018–2020-жылга карата каржылоо кыскартылууда.
Быйыл программанын бюджети 11 миллион долларды түзүп, пландалган иш чараларды ишке ашырууга 1,8 миллион доллар жетишпейт.
«2017–2021-жылга карата ВИЧ/СПИД менен күрөшүүгө багытталган мамлекеттик программа иштелип чыккан.
Ал азыр Каржы министрлигинин кароосунда.
Эгер ал ишке аша турган болсо, анда бул илдетке каршы күрөштү мамлекет колго алып, Глобалдуу фонд каржылоону азайтып баштайт» — дейт борбордун жетекчиси."""
# example_tokenizer = TreebankWordTokenizer()
# custom_tokenize = lambda sentence: list(example_tokenizer.span_tokenize(sentence))
# print("Default NLTK word tokenizer")
# print(example_tokenizer.tokenize(test_text))
# print(custom_tokenize(test_text))
# print()
example_tokenizer2 = ApertiumSimpleTokenizer(lang="kir", already_installed="True")
custom_tokenize2 = lambda sentence: list(example_tokenizer2.span_tokenize(sentence))
print("Apertium-based word tokenizer")
print(example_tokenizer2.tokenize(test_text))
print(custom_tokenize2(test_text))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment