from typing import List import million.analyze.message_evaluation as msg_val from million.model.message import Message def check_extra_or_missing_letter(word: str, reference: str) -> bool: """ Cette méthode vérifie si la str word contient une et une seule lettre de trop ou de moins par rapport à la str reference """ len_word = len(word) len_ref = len(reference) if abs(len_word - len_ref) != 1: return False shortest = word if len_word < len_ref else reference longest = word if len_word > len_ref else reference for i in range(len(shortest)): if shortest[i] != longest[i]: return shortest[i:] == longest[i + 1 :] return True def check_single_letter_differ(word: str, reference: str) -> bool: """ Cette méthode vérifie si la str word contient une et une seule lettre différente par rapport à la str reference """ return sum(1 for x, y in zip(reference, word) if x != y) == 1 def check_letter_swap(word: str, reference: str) -> bool: """ Cette méthode vérifie si la str word contient un et un seul échange de lettres consécutives par rapport à la str reference """ if len(word) != len(reference): return False for i in range(len(word) - 1): if word[i] != reference[i]: return word[i + 1] + word[i] + word[i + 2 :] == reference[i:] return False def check_typo(word: str, reference: str) -> bool: """ Cette méthode vérifie si la str word contient une typo en se référant à la str reference """ if len(reference) == len(word): return check_single_letter_differ(word, reference) or check_letter_swap( word, reference ) else: return check_extra_or_missing_letter(word, reference) def _check_message_concatenation(messages: List[Message], index: int, expected: int) -> bool: """ Cette méthode détermine si la liste messages contient le compte expected à partir de l'index donné en concaténant les valeurs des messages suivants. Cette méthode permet de trouver un compte qui a été étalé sur plusieurs messages """ reference = str(expected) testing = "" offset = 0 while len(testing) < len(reference): next_message = messages[index + offset] offset += 1 if next_message.sender_name == messages[index].sender_name: testing += str(msg_val.get(next_message)) return testing == reference def _heavy_check(messages: List[Message], index: int, expected: int) -> bool: """ Cette méthode détermine si la liste messages contient le compte expected à partir de l'index donné. Elle utilise pour cela des méthodes complexes qui ne permettent de trouver un résultat seulement si on est sortis du cas nominal """ # TODO # - créer une méthode pour gérer le cas où plusieurs comptages sont contenus dans le même corps de message # - créer une méthode pour le cas où les chiffres sont représentés par un substitut au sein du corps du message # i.e. un nombre écrit en toutes lettres (français ou breton), 🍁 pour 420, @Elias Cheddar pour 69 m = messages[index] word = str(msg_val.get(m)) return _check_message_concatenation(messages, index, expected) or \ check_typo(word, str(expected)) and msg_val.get(messages[index+1]) == expected+1 def _check_value_around(messages, index, expected, amplitude_after, amplitude_before): for i in range(1, amplitude_after + 1): if index + i < len(messages) and expected == msg_val.get(messages[index + i]): return index + i for i in range(1, amplitude_before + 1): if expected == msg_val.get(messages[index - i]): return index - i return None def search_value_at(messages, index, expected, do_heavy_check=True, amplitude_after=1000, amplitude_before=10): """ Cette méthode détermine si la liste messages contient le compte expected à partir de l'index donné. Le paramètre amplitude détermine la plage où effectuer les recherches autour de l'index donné. Le paramètre do_heavy_check précise si on doit pousser l'analyse avec des méthodes plus lourdes en cas d'échec """ # Si le message courant contient la valeur, on renvoie curr_value = msg_val.get(messages[index]) if expected == curr_value: return index # Sinon on regarde aux alentours jump_index = _check_value_around(messages, index, expected, amplitude_after, amplitude_before) if jump_index is not None: return jump_index # Enfin, si on ne trouve pas la valeur à l'index donné et dans l'amplitude donnée # On performe une vérification lourde à cet endroit if do_heavy_check and _heavy_check(messages, index, expected): return index # Si tout cela n'a rien donné, on renvoie None return None