Skip to content
Snippets Groups Projects
Commit 282973a6 authored by BIRK Renaud's avatar BIRK Renaud
Browse files

Refactorisation de l'identification

parent c6973aa6
No related branches found
No related tags found
No related merge requests found
......@@ -7,13 +7,14 @@ class Identification:
Classe de gestion de l'identification et du regroupement des données.
:param groups: Une liste de groupes trouvés à l'issue de l'OCR
:param csv_path: Un chemin vers le fichier CSV contenant les informations
sur les marques référencées.
sur les marques référencées
:param device: Un dispositif
"""
def __init__(self, groups: List[Group], csv_path="data/csv") -> None:
def __init__(self, groups: List[Group], csv_path="data/csv", device=Device()) -> None:
self.groups = groups
self.csv_path = csv_path
self.device = Device()
self.device = device
def extract_column(self, input_file_path: str, output_file_path: str, column_index: int, drop_duplicates=True, case_insensitive=True) -> None:
"""
......@@ -48,10 +49,8 @@ class Identification:
"""
Vérifie si une valeur fait partie d'une colonne d'un fichier séparé par
des virgules (comma-separated values)
:param input_file_path: Un chemin vers le fichier à traiter
:param output_file_path: Le chemin où générer le fichier
:param file_path: Un chemin vers le fichier à traiter
:param column_index: Indice de la colonne (en partant de 0)
:param drop_duplicates: Enlève les répétitions
:param case_insensitive: Ne respecte pas la casse
"""
with open(file_path, 'r', encoding='utf-8') as file:
......@@ -68,7 +67,7 @@ class Identification:
"""
Renvoie `True` si le mot passé en entrée correspond à une marque
présente dans la base de données des marques connues d'Oxyledger.
:word: Un mot à chercher
:param word: Un mot à chercher
"""
return self.value_in_column(self.csv_path + "/device_model_extracted_brand_name.csv", word)
......@@ -76,54 +75,54 @@ class Identification:
"""
Renvoie `True` si le mot passé en entrée correspond à un fabricant
présent dans la base de données des fabricants connus d'Oxyledger.
:word: Un mot à chercher
:param word: Un mot à chercher
"""
return self.value_in_column(self.csv_path + "/device_model_extracted_manufacturer_name.csv", word)
def est_code_barre(self, chaine: str, prefix="") -> bool:
def is_barcode(self, string: str, prefix="") -> bool:
"""
Teste si la chaîne donnée en paramètres est un code barre en prenant
en compte d'éventuelles erreurs liées à la phase d'OCR.
:param chaine: Une chaîne de caractères à tester
:param string: Une chaîne de caractères à tester
:param prefix: Le préfixe à trouver
"""
# Initialisation
est_prefixee = False
est_prefixee_erreur_gauche = False
is_prefix = False
is_prefix_left_error = False
# Recherche d'un code barre par son préfixe
if prefix:
# Cas classique
est_prefixee = chaine[0:len(prefix)] == prefix
is_prefix = string[0:len(prefix)] == prefix
# Cas où on reconnait 01) au lieu de (01)
est_prefixee_erreur_gauche = chaine[0: len(prefix) - 1] == prefix[1:]
is_prefix_left_error = string[0: len(prefix) - 1] == prefix[1:]
# Recherche d'un code barre par le format de son préfixe sur au moins 4
# caractères
elif len(chaine) >= 4:
elif len(string) >= 4:
# Reconnaît le motif (XY) avec X et Y des chiffres
motif_prefixe = re.compile(r"\(\d{2}\)(.*)")
prefix_pat = re.compile(r"\(\d{2}\)(.*)")
# Reconnaît le motif XY) avec X et Y des chiffres
motif_prefixe_erreur_gauche = re.compile(r"\d{2}\)(.*)")
prefix_pat_left_error = re.compile(r"\d{2}\)(.*)")
# Cas classique
est_prefixee = motif_prefixe.fullmatch(chaine)
is_prefix = prefix_pat.fullmatch(string)
# Cas où on reconnait XY) au lieu de (XY) avec X et Y des chiffres
est_prefixee_erreur_gauche = motif_prefixe_erreur_gauche.fullmatch(chaine)
is_prefix_left_error = prefix_pat_left_error.fullmatch(string)
# La fonction renvoie vraie si l'une ou l'autre des conditions est remplie
return est_prefixee or est_prefixee_erreur_gauche
return is_prefix or is_prefix_left_error
def val_marqueur(self, chaine: str, marqueur: str) -> str:
def is_tag(self, string: str, tag: str) -> str:
"""
Teste si la chaîne donnée en paramètres contient un marqueur et renvoie
sa valeur ou `None` si le marqueur et/ou la valeur n'a/n'ont été(s)
trouvé(s)
:param chaine: Une chaîne de caractères à tester
:param marqueur: Le marqueur à trouver
trouvé(s).
:param string: Une chaîne de caractères à tester
:param tag: Le marqueur à trouver
"""
mots = chaine.split(" ", 1)
mot1 = mots[0]
words = string.split(" ", 1)
word_left = words[0]
# S'il y a au moins deux mots et que le premier contient le marqueur
if len(mots) == 2 and marqueur in mot1:
val = mots[1].strip()
if len(words) == 2 and tag.lower() in word_left.lower():
val = words[1].strip()
# Si la valeur du marqueur fait aux moins 2 caractères, on peut la
# considérer comme pertinente.
if len(val) > 2:
......@@ -133,25 +132,25 @@ class Identification:
else:
return None
def est_date(self, chaine: str) -> bool:
def is_date(self, string: str) -> bool:
"""
Renvoie `True` si la chaîne de caractères passée est une date au format
YYYY-MM-DD (où YYYY est l'année, MM le numéro du mois et DD le numéro du
jour du mois)
:param chaine: La chaîne de caractères à tester
jour du mois).
:param string: La chaîne de caractères à tester
"""
motif = re.compile(r'\d{4}-\d{2}-\d{2}')
return bool(motif.fullmatch(chaine))
pat = re.compile(r'\d{4}-\d{2}-\d{2}')
return bool(pat.fullmatch(string))
def est_utile(self, chaine: str) -> bool:
def is_useful(self, string: str) -> bool:
"""
Renvoie `True` si la chaîne de caractères passée n'est ni un numéro de
lot, ni un code barre et ni une date (auquel cas il s'agit d'une
information pertinente)
:param chaine: La chaîne de caractères à tester
information pertinente).
:param chaine: Une chaîne de caractères à tester
"""
est_numero_de_lot = self.val_marqueur(chaine, "lot")
return not (est_numero_de_lot or self.est_code_barre(chaine) or self.est_date(chaine))
is_batch_number = self.is_tag(string, "lot")
return not (is_batch_number or self.is_barcode(string) or self.is_date(string))
def identify(self) -> Device:
"""
......@@ -170,17 +169,17 @@ class Identification:
if subgroup.string:
# Si la chaîne analysée commence par (01), alors on retire
# le préfixe "(01)", on obtient ainsi l'IUD
if self.est_code_barre(subgroup.string, "(01)"):
if self.is_barcode(subgroup.string, "(01)"):
self.device.uid = subgroup.string[3:].split("(", 1)[0].replace(" ", "").replace(")", "")
else:
# Si la chaîne analysée est aux abords d'un marqueur
# "ref", alors il s'agit d'une référence
ref = self.val_marqueur(subgroup.string, "ref")
ref = self.is_tag(subgroup.string, "ref")
if ref:
self.device.ref = ref
# Si on a trouvé la référence du dispositif, on lui
# ajoute
if self.est_utile(subgroup.string):
if self.is_useful(subgroup.string):
if len(subgroup.string) > 2:
if self.is_brand_name(subgroup.string):
self.device.brand_name = subgroup.string
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment