IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Regex sur parenthèses


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 333
    Par défaut Regex sur parenthèses
    Hello,
    Dans dans un fichier.rtf, le script doit détecter s'il manque une parenthèse ouvrante avant un mot en majuscule de 1 à 4 lettres suivi d'une parenthèse fermante.
    exemple de ligne : Louise, N : 4-5-1736 (H), Pa : Pierre (DSC) ; Ma : SOULAINE Louise BH)
    Dans ce cas, la fonction détecte une erreur et affiche le contenu de la ligne.

    Le pattern = r'(?<!\()[A-Z]{1,4}\)'
    • (?<!\(): Assure qu'il n'y a pas de parenthèse ouvrante avant la position actuelle.
    • [A-Z]{1,4}: Correspond à un mot en majuscule de 1 à 4 lettres.
    • \): Correspond à une parenthèse fermante.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def cherche_parenthese_ouvrante_hameau_rtf(targetFile):     
        with open(targetFile, 'r', encoding='latin-1') as file:
        rtf_content = file.read()
     
        #pattern = r'(?<!\()[A-Z]{1,4}\)'
        pattern = r'(?<!\()[A-Z]{1,4}\)'
        matches = re.finditer(pattern, rtf_content)
     
        for match in matches:
            #print(match)
            start = match.start()
            #print(rtf_content[:start])  # ligne concernée
            print(match.group())
            if '(' not in rtf_content[:start]:
                print(f"Erreur détectée : {match.group()} à la position {start}")
    Je ne parviens pas au résultat souhaité.
    Est-ce le pattern ou le code !?
    Alain

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 762
    Par défaut
    Salut,

    DSC) est une séquence qui matche: il commence par D (qui n'est pas "(") et comprends 2 caractères avant ")". Donc c'est le pattern.
    Personnellement, pour ce genre de tests, je préfère coder plutôt que passer par des regexp (je n'en ai jamais eu trop besoin pour y passer du temps).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 333
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Salut,

    DSC) est une séquence qui matche: il commence par D (qui n'est pas "(") et comprends 2 caractères avant ")". Donc c'est le pattern.
    Personnellement, pour ce genre de tests, je préfère coder plutôt que passer par des regexp (je n'en ai jamais eu trop besoin pour y passer du temps).
    - W
    Bonjour wiztricks,
    Sur tes conseils, j'ai codé ce script "qui ne fonctionne pas".
    Pourrais-tu m'aider à le debugger ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    def recherche_parenthese_rtf(targetFile):
     
        with open(targetFile, 'r', encoding='latin-1') as file:
            rtf_content = file.read()
     
            # Convertir le contenu RTF en texte brut
            rtf_text = rtf_to_text(rtf_content)
     
            errors = []
            i = 0
            while i < len(rtf_text):
                #print(len(rtf_content))
                if rtf_text[i] == ')':
                    # Vérifier s'il y a une parenthèse ouvrante avant cette parenthèse fermante
                    has_opening_parenthesis = False
     
                    for j in range(i - 1, -1, -1):
                        if rtf_text[j] == '(':
                            has_opening_parenthesis = True
                            break
                        # Arrêter la boucle si un caractère non alphabétique est rencontré
                        if not rtf_text[j].isalpha() and rtf_text[j] != ' ':
                            break
                    if not has_opening_parenthesis:
                        errors.append((rtf_text[i-3:i+1], i))
                i += 1
     
            for error in errors:
                print(f"Erreur détectée : {rtf_text}")

  4. #4
    Expert confirmé Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 986
    Par défaut
    Pour que ça marche avec une pattern, il te faudrait \b(?<!\()[A-Z]{1,4}\) (le word-boundary \b permet de "caler" la position au début des lettres en supposant qu'à la place de la parenthèses ouvrante il y ait quelque chose qui ne soit pas une lettre, un chiffre ou un souligné).


    Plus robuste (sans supposition en s'en tenant strictement à ta description); (?<![(A-Z])[A-Z]{1,4}\)|[A-Z]{5}\).

    Si ton fichier est agencé en lignes, n'utilise pas file.read() et lis le ligne par ligne en les filtrants avec re.search et la pattern.

  5. #5
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    salut,

    et simplement compter le nombre de parenthèses ouvrantes/fermantes ça ne fait pas le job ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    >>> s = "Louise, N : 4-5-1736 (H), Pa : Pierre (DSC) ; Ma : SOULAINE Louise BH)"
    >>> s.count('(') == s.count(')')
    False
    >>> re.findall(r'\([A-Z]{1,4}\)', s)
    ['(H)', '(DSC)']
    >>> re.findall(r'[^(A-Z][A-Z]{1,4}\)', s)
    [' BH)']

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 333
    Par défaut
    Citation Envoyé par CosmoKnacki Voir le message
    Pour que ça marche avec une pattern, il te faudrait \b(?<!\()[A-Z]{1,4}\) (le word-boundary \b permet de "caler" la position au début des lettres en supposant qu'à la place de la parenthèses ouvrante il y ait quelque chose qui ne soit pas une lettre, un chiffre ou un souligné).

    Plus robuste (sans supposition en s'en tenant strictement à ta description); (?<![(A-Z])[A-Z]{1,4}\)|[A-Z]{5}\).
    Si ton fichier est agencé en lignes, n'utilise pas file.read() et lis le ligne par ligne en les filtrants avec re.search et la pattern.
    Bonjour à tous et merci pour vos propositions
    Le code suivant me donnerait entière satisfaction, MAIS la ligne print(f"Ligne détectée : {clean_line}") retourne un résultat qui n'est pas satisfaisant.
    L'expression régulière doit supprimer toutes les balises RTF
    Dans l'exemple suivant:
    {\pard\ql\f0\sa180\li0\fi0 2b : Louise, N : 4-5-1736 (BH), Pa : Pierre (BH) ; Ma : Louise BH)\par}
    le résultat conserve {

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
        def remove_rtf_tags(text):
            # Expression régulière pour supprimer les balises RTF
            clean_text = re.sub(r'{\\[^ ]+}|\\[^ ]+}|\\[^ ]+', '', text)
            return clean_text.strip()
     
     
        #=============================================================================
        def cherche_parenthese_ouvrante_hameau_rtf(targetFile):  
            # détecte l'absence de parenthèse ouvrante dans toutes les occurrences d'une chaine. 
     
            #    pattern = r'\b(?<!\()[A-Z]{1,4}\)'
            #    \b            Détermine la position du début des lettres 
            #    (?<!\()       Assure qu'il n'y a pas de parenthèse ouvrante avant la position actuelle
            #    [A-Z]{1,4}    Correspond à un mot en majuscule de 1 à 4 lettres
            #    \)            Correspond à une parenthèse fermante
     
     
            with open(targetFile, 'r', encoding='latin-1') as file:
                rtf_content = file.readlines()
     
                pattern = r'\b(?<!\()[A-Z]{1,4}\)'
     
                for i, line in enumerate(rtf_content):
                    matches = re.finditer(pattern, line)
                    for match in matches:
                        print(f"ERREUR parenthèse : {line.strip()}") 
                        clean_line = remove_rtf_tags(line.strip())
                        print(f"Ligne détectée : {clean_line}")
    > CosmoKnacki
    Est ce que la lecture ligne par ligne avec re.search et la pattern, est préférable à readlines() ?

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 762
    Par défaut
    Citation Envoyé par alainb Voir le message
    Pourrais-tu m'aider à le debugger ?
    Le plus important dans ce détail du programme sera comment on va pouvoir tester ou pas et de la pertinence du plan de tests.

    Si je prends comme test la chaine de caractères:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    line = "Louise(H), Pa (Hh) Pierre (ABCDE) xBH) BH)"
    le code pourrait être:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    i = len(line)
    while True:
        b = line.rfind(')', 0, i)
        if b == -1:
            break
        a = line.rfind('(', 0, b)
        if a == -1:
            break
        if not (1 <= b-a <= 4):
            print('error1:', line[a:b+1])
        else:
            for j in range(a+1, b):
                if not('A' <= line[j] <= 'Z'):
                    print('error2:',line[j], line[a:b+1])
                    break
        i = b-1
    qui affiche:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    error1: (ABCDE) xBH) BH)
    error1: (ABCDE) xBH)
    error1: (ABCDE)
    error2: h (Hh)
    Si on est content, on améliore la remontée des erreurs et on emballe le tout dans une fonction.

    On pourra noter qu'avec le pattern proposé par CosmoKnacki, manque des cas (de mon exemple)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> re.findall(r'\b(?<!\()[A-Z]{1,4}\)', line)
    ['BH)']
    ce qui n'a aucune importance car tout dépend de comment le problème a été analysé. Ce qui suppose travailler sur les données... pour définir la ou les solutions plutôt que de se plier à des desiderata qui ne sont peut être pas si fondés que çà.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 333
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Le plus important dans ce détail du programme sera comment on va pouvoir tester ou pas et de la pertinence du plan de tests.
    Le cas extrême qui pourrait survenir est LouiseH), Pa (Hh) Pierre ABCD)
    Donc le pattern = r'(?<![(A-Z])[A-Z]{1,4}\)|[A-Z]{4}\)' est celui qu'il me faut
    Merci pour ta vigilance quant à la présentation de mes petits problèmes. J'ai effectué une analyse poussée des données sources, je suis certain du résultat avec le pattern.

    Reste le dernier sujet présenté ci-dessus.
    Dans la chaine suivante : {\pard\ql\f0\sa180\li0\fi0 2b : Louise, N : 4-5-1736 (BH), Pa : Pierre (BH) ; Ma : Louise BH)\par}
    je veux supprimer toutes les balises RTF
    Le pattern = '\\[^ ]+}|{\\[^ ]+}|\\[^ ]+|}\{' conserve {
    As-tu une idée de mon erreur ?
    Alain

  9. #9
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 762
    Par défaut
    Citation Envoyé par alainb Voir le message
    As-tu une idée de mon erreur ?
    Quel est le rapport avec le sujet initial?

    Une recherche sur Internet me dit que récupérer le texte d'un RTF est peut être plus ardu que ce dans quoi vous vous êtes lancé.

    Mais on est toujours dans la même logique: plan de tests et valider les solutions en explorant ce qui a été fait (sur Internet).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  10. #10
    Expert confirmé Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 986
    Par défaut
    Si le but du jeu est de récupérer le texte d'un fichier rtf, je te déconseille de le faire "à la main". Python a une tripotée de modules, à tous les coups il y en aura un pour extraire du texte d'un rtf. Parce que si tu comptes faire ça à coup de regex et que ton texte contient des caractères en dehors de la plage ASCII (ce qui est représenté en rtf par des séquences d'échappement), ces derniers vont tous gicler. Et aucune assurance que des noms de font ne se retrouvent pas à flotter dans l'espace au milieu de ton texte brut.

    Je n'ai jamais eu à le faire, mais après une recherche rapide: https://pypi.org/project/striprtf/ qui a l'air plutôt simple.

    Du coup, si tu dois faire cette extraction au préalable, la lecture du fichier ligne par ligne n'est plus d'actualité puisque ce genre de module doit pouvoir traiter des "balises" rtf qui peuvent s'étendre sur plusieurs lignes.

Discussions similaires

  1. [RegEx] Regex sur un retour d'exec()
    Par Er3van dans le forum Langage
    Réponses: 1
    Dernier message: 18/04/2008, 15h19
  2. [RegEx] Tester un regex sur un champ de formulaire
    Par Olivier Regnier dans le forum Langage
    Réponses: 1
    Dernier message: 11/11/2007, 23h45
  3. [RegEx] Regex sur une fonction mathématique
    Par raptorman dans le forum Langage
    Réponses: 1
    Dernier message: 02/11/2007, 10h04
  4. [RegEx] regex sur présence d'une apostrophe
    Par Pitou5464 dans le forum Langage
    Réponses: 3
    Dernier message: 30/08/2007, 11h19
  5. Regex sur adresse IP
    Par lobiman dans le forum Langage
    Réponses: 5
    Dernier message: 12/09/2006, 16h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo