BRAXEN_LOCATION = "/Users/joregan/Playing/braxen/dict/braxen-sv.tsv"
from pathlib import Path

BRAXEN_PATH = Path(BRAXEN_LOCATION)
def has_boundary(phones):
    boundaries = ["|", "~", "-"]

    for phone in phones:
        if phone in boundaries:
            return True
    return False
def clean_phones(phones):
    boundaries = ["|", "~", "-", "."]
    out_phones = []
    for phone in phones:
        if phone not in boundaries:
            out_phones.append(phone)
    return out_phones
    
errata = {
    "10-killarna": (11, ".", "-"), # 825641
    "2-dokumentär": (8, ".", "-"), # 825341
    "70-talisternas": (11, ".", "-"), # 806484
}
reverse = {}

with open(BRAXEN_LOCATION) as inf:
    for line in inf.readlines():
        line = line.strip()
        if line.startswith("#"):
            continue
        parts = line.split("\t")
        word = parts[0]
        phone_str = parts[1]

        if word in errata:
            mod = errata[word]
            if phone_str[mod[0]] == mod[1]:
                chars = list(phone_str)
                chars[mod[0]] = mod[2]
                phone_str = "".join(chars)
        
        phones = phone_str.split(" ")
        if has_boundary(phones):
            continue
        if word.startswith("-"):
            continue
        if word.startswith("\ufb01"):
            # fi ligature
            continue
        if not phone_str in reverse:
            reverse[phone_str] = []
        if word not in reverse[phone_str]:
            reverse[phone_str].append(word)
import json

with open("braxen-simple-reverse.json", "w") as outf:
    json.dump(reverse, outf, indent=4)
LANG_FIXES = """
playback 376738 eng
playboy 376739 eng
play-off 782183 eng
playa 376734 spa
Halloweens 880274 eng
återvändaren 837944 swe
temporomandibular 718339 swe
# (maybe lat? definitely not eng with that pronunciation)
командитното 831898 bul
Štépnička 869924 cze
Štépničkas 869925 cze
Škoda 733908 cze
Bandsåg 739294 swe
# also 'VB PRT AKT' -> NN UTR SIN IND NOM (?)
Gomez 634927 spa
Gražinytė 877254 lit
Gražinytės 877255 lit
"""
# wget w|get 732342 swe|eng
# väggsquat vägg|squat 828971 swe|eng
# personlighetsoro personlighet|soro 878836 swe|ara
# påklädningsapraxi påklädnings|apraxi 839252 swe|lat
def split_list(input, delimiters):
    output = []
    current = []
    for item in input:
        if item in delimiters:
            if current:
                output.append(current)
                current = []
        else:
            current.append(item)
    if current:
        output.append(current)
    return output
assert split_list('n \'o l | n "o l - m ,a rt . rs ex n'.split(" "), ["|", "~", "-"]) == [['n', "'o", 'l'], ['n', '"o', 'l'], ['m', ',a', 'rt', '.', 'rs', 'ex', 'n']]
$ grep '^[0-9]-[0-9]-' ~/Playing/braxen/dict/braxen-sv.tsv |awk -F'\t' '{print $1}'|awk -F'-' '{print $3}'|sort|uniq
1
åringar
årsåldern
förlust
förlusten
förluster
försvar
ledning
ledningen
mål
målen
målet
målskytt
målskytten
match
matchen
matcher
reducering
reduceringen
seger
segern
skola
smällen
underläge
underlägen
underläget
vinsten
compounds = {}
hyphenated = {}
already_split = {}
first_only = {}
second_only = {}

def resolve_parts(parts, word, reverse):
    """Try to greedily consume `word` using phone-parts; backtrack on failure.
    Returns list of word-parts covering the whole word, or None."""
    def rec(i, rest):
        if i == len(parts):
            return [] if rest == "" else None
        part_str = " ".join(parts[i])
        for cand in reverse.get(part_str, []):
            if rest.startswith(cand):
                tail = rec(i + 1, rest[len(cand):])
                if tail is not None:
                    return [cand] + tail
        return None
    return rec(0, word)

with open(BRAXEN_LOCATION) as inf:
    for line in inf.readlines():
        line = line.strip()
        if line.startswith("#"):
            continue
        parts_raw = line.split("\t")
        word = parts_raw[0]
        phone_str = parts_raw[1]

        phones = phone_str.split(" ")
        if not has_boundary(phones):
            continue
        if word.startswith("-"):
            continue
        if word.startswith("\ufb01"):  # fi ligature
            continue
        if word[0].isdigit():
            continue

        parts = split_list(phones, ["|", "~", "-"])

        if "-" in word:
            word_parts = word.split("-")
            if len(word_parts) == len(parts):
                hyphenated[word] = word_parts
            continue
        if " " in word:
            word_parts = word.split(" ")
            if len(word_parts) == len(parts):
                already_split[word] = word_parts
            continue

        # Full mapping: every phone-part maps to a word-part covering the whole word.
        resolved = resolve_parts(parts, word, reverse)
        if resolved is not None:
            compounds[word] = resolved
            continue

        # Two-part fallback: only meaningful when there are exactly two phone-parts.
        if len(parts) == 2:
            first_str = " ".join(parts[0])
            second_str = " ".join(parts[1])

            first_match = next(
                (w for w in reverse.get(first_str, []) if word.startswith(w)),
                None,
            )
            second_match = next(
                (w for w in reverse.get(second_str, []) if word.endswith(w)),
                None,
            )

            if first_match is not None:
                first_only[word] = [first_match, word[len(first_match):]]
            if second_match is not None:
                second_only[word] = [word[:len(word) - len(second_match)], second_match]
len(hyphenated), len(already_split), len(compounds)
(10891, 572, 192)
with open("braxen-compounds1.json", "w") as outf:
    json.dump(compounds, outf, indent=4)
with open("braxen-hyphenated1.json", "w") as outf:
    json.dump(hyphenated, outf, indent=4)
with open("braxen-already-split1.json", "w") as outf:
    json.dump(already_split, outf, indent=4)
with open("braxen-first-only1.json", "w") as outf:
    json.dump(first_only, outf, indent=4)
with open("braxen-second-only1.json", "w") as outf:
    json.dump(second_only, outf, indent=4)