Verified Commit d63945e3 authored by Jakob Moser's avatar Jakob Moser
Browse files

Try implementing better heuristic

parent 82acdbb9
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
from functools import reduce

REPLACEMENTS = {
    "ä": "(ä|ae|a)",
    "ö": "(ö|oe|o)",
    "ü": "(ü|ue|u)",
    "ß": "(ß|ss)",
    "Ä": "(Ä|Ae|A)",
    "Ö": "(Ö|Oe|O)",
    "Ü": "(Ü|Ue|U)",
    "": "(ẞ|SS)",
}


def to_compatibility_regex(evil_unicode_string: str) -> str:
    """
    > Schon unsere Großväter wussten, was gut ist: Ein selbstbereiteter String mit irgendwelchen Zeichen drin.
    > Doch sie wussten auch ein Lied davon zu singen, wie schwer es ist, so einen String zu verarbeiten.
    > Ja, so war es damals.
    >
    > Und heute?

    Converts a normal string, which might contain evil characters, such as ä, ö, ü, or ß, to a regular
    expression matching variants of those characters which you can use if you are a German bank and have
    never heard of Unicode before.

    :see: https://www.youtube.com/watch?v=P56pk5mDewU
    """
    return reduce(
        lambda string, replacement: string.replace(*replacement),
        REPLACEMENTS.items(),
        evil_unicode_string,
    )
+22 −3
Original line number Diff line number Diff line
@@ -4,9 +4,10 @@ from typing import TYPE_CHECKING, Literal, Self

from babel.numbers import format_currency
from sqlalchemy import select
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.orm import Mapped, QueryableAttribute, mapped_column, relationship

from poolpay import db
from poolpay.fints.to_compatibility_regex import to_compatibility_regex
from poolpay.model.Base import Base

if TYPE_CHECKING:
@@ -133,9 +134,19 @@ class Person(Base):

        If no persons can be found or there are too many plausible matches, None is returned.
        """
        # TODO Improve heuristics

        # We currently ignore middle names
        first_name, *_, last_name = full_name.split(" ")

        # We try to deal with umlauts etc.
        first_name_regex = to_compatibility_regex(first_name)
        last_name_regex = to_compatibility_regex(last_name)

        def _try_get_single_person(
            field: QueryableAttribute, regex: str
        ) -> Self | None:
            persons = (
            db.session.execute(select(cls).where(cls.name == full_name.split(" ")[0]))
                db.session.execute(select(cls).where(field.regexp_match(regex)))
                .scalars()
                .all()
            )
@@ -144,3 +155,11 @@ class Person(Base):
                return None

            return persons[0]

        potential_last_name_match = _try_get_single_person(
            cls.cl_account_name, last_name_regex.lower()
        )
        if potential_last_name_match:
            return potential_last_name_match

        return _try_get_single_person(cls.name, first_name_regex)