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 :

Négation de REGEX


Sujet :

Python

  1. #1
    Membre confirmé
    Inscrit en
    Novembre 2010
    Messages
    176
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 176
    Par défaut Négation de REGEX
    Bonsoir.

    Exemple de texte:

    b'STN--- WBAN YEARMODA TEMP DEWP SLP STP VISIB WDSP MXSPD GUST MAX MIN PRCP SNDP FRSHTT\n486200 99999 20110101 79.3 24 74.5 24 1007.2 8 1006.2 8 6.6 24 2.2 24 7.0 999.9 87.8 74.1 0.00G 999.9 010000\n486200 99999 20110102 79.7 24 74.9 24 1007.8 8 1006.9 8 6.1 24 2.8 24 8.0 15.0 91.9 74.8 0.00G 999.9 010010\n486200 99999 20110103 77.5 24 73.6 24 1008.5 8 1007.6 8 6.0 24 2.8 24 6.0 999.9 83.7 73.4* 0.68G 999.9 010000\n486200 99999 20110104 81.2 24 75.0 24 1007.7 8 1006.8 8 6.3 24 3.0 24 5.1 999.9 89.6* 73.0 0.14G 999.9 010010\n486200 99999 20110105 79.7 24 74.8 24 1007.8 8 1006.8 8 7.0 24 2.4 24 6.0 999.9 87.8 73.0 0.57G 999.9 010000\n486200 99999 20110106 77.4 24 74.6 24 1008.8 8 1007.9 8 6.0 24 1.5 24 4.1 999.9 81.0 73.2 0.16G 999.9 010000\n486200 99999 20110107 77.7 24 75.0 24 1008.9
    Dans le texte ci-dessus, retrouver toutes les dates (ex: '20110101') et les précipitations qui sont les seules digits accompagnées d'une lettre (ex: '0.57G') est possible avec la regex:

    (\d{8}|\d{1,2}\.\d{1,2}[ABCDEFG])
    Mais je veux en fait, l'inverse, c'est à dire retrouver tout sauf le résultat de cette regex. Je m'attendais à ce que:

    (?!(\d{8}|\d{1,2}\.\d{1,2}[ABCDEFG]))
    fonctionne, mais non ...

    Avez-vous des suggestions?

    Merci

  2. #2
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    On peut "éplucher" une chaine de la façon suivante:

    Prenons un exemple plus simple que le tien:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    chaine = "aaaaaXXXbbbbbbXXXccccccccc"
    motif = r"XXX"
    On compile le motif: c'est important pour pouvoir utiliser l'option "pos" de search.

    On va maintenant chercher toutes les sous-chaines correspondant au motif, mais en renvoyant leurs indices de début et de fin:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    result = []
    pos = 0
    while True:
        m = rc.search(chaine, pos)
        if m == None:
            break # il n'y a plus rien de trouvé après pos
        pos = m.end()
        result.append([m.start(), pos])
     
    print(result)
    Ce qui donnera ici comme résultat:

    On a bien: chaine[5:8] == "XXX" et chaine[14:17] == "XXX"


    Connaissant les adresses des séquences trouvés, on peut en déduire les sous-chaines qui n'en font pas partie:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    print(chaine[0:5])
    aaaaa
    print(chaine[8:14])
    bbbbbb
    print(chaine[17:len(chaine)])
    ccccccccc
    Voilà comment on peut automatiser cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    alt = []
    if len(result) > 0:
        alt.append([0, result[0][0]])
        for i in range(0, len(result) - 1):
            alt.append([result[i][1], result[i + 1][0]])
        alt.append([result[-1][1], len(chaine)])
    print(alt)
    Ce qui donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [[0, 5], [8, 14], [17, 26]]
    On obtient bien toutes les sous-chaines qui ne sont pas les séquences satisfaisant au motif regex.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par tallent_e Voir le message
    Bonsoir.

    Exemple de texte:
    Dans le texte ci-dessus, retrouver toutes les dates (ex: '20110101') et les précipitations qui sont les seules digits accompagnées d'une lettre (ex: '0.57G') est possible avec la regex:
    Mais je veux en fait, l'inverse, c'est à dire retrouver tout sauf le résultat de cette regex. Je m'attendais à ce que:
    fonctionne, mais non ...
    Avez-vous des suggestions?
    Merci
    Bonjour,

    Est-ce ceci que vous cherchez à obtenir :

    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
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
     
    import re
     
    text = (
        "STN--- WBAN YEARMODA TEMP DEWP SLP STP VISIB WDSP MXSPD "
        "GUST MAX MIN PRCP SNDP FRSHTT\n486200 99999 20110101 79.3 "
        "24 74.5 24 1007.2 8 1006.2 8 6.6 24 2.2 24 7.0 999.9 87.8 "
        "74.1 0.00G 999.9 010000\n486200 99999 20110102 79.7 24 74.9 "
        "24 1007.8 8 1006.9 8 6.1 24 2.8 24 8.0 15.0 91.9 74.8 0.00G "
        "999.9 010010\n486200 99999 20110103 77.5 24 73.6 24 1008.5 "
        "8 1007.6 8 6.0 24 2.8 24 6.0 999.9 83.7 73.4* 0.68G 999.9 "
        "010000\n486200 99999 20110104 81.2 24 75.0 24 1007.7 8 1006.8 "
        "8 6.3 24 3.0 24 5.1 999.9 89.6* 73.0 0.14G 999.9 010010\n486200 "
        "99999 20110105 79.7 24 74.8 24 1007.8 8 1006.8 8 7.0 24 2.4 "
        "24 6.0 999.9 87.8 73.0 0.57G 999.9 010000\n486200 99999 "
        "20110106 77.4 24 74.6 24 1008.8 8 1007.9 8 6.0 24 1.5 24 "
        "4.1 999.9 81.0 73.2 0.16G 999.9 010000\n486200 99999 20110107 "
        "77.7 24 75.0 24 1008.9"
    )
    # split around regexp
    res = re.split(r"\d{8}|\d{1,2}\.\d{1,2}[ABCDEFG]", text)
    # list
    print(res)
    # str
    print("".join(res))
    Notez que (?!expr) est la négation d'un lookahead, extrait de la doc officielle :

    (?=...)
    Matches if ... matches next, but doesn’t consume any of the string. This is called a lookahead assertion. For example, Isaac (?=Asimov) will match 'Isaac ' only if it’s followed by 'Asimov'.
    (?!...)
    Matches if ... doesn’t match next. This is a negative lookahead assertion. For example, Isaac (?!Asimov) will match 'Isaac ' only if it’s not followed by 'Asimov'.
    doc officielle : https://docs.python.org/3/library/re.html

    bon courage.

    @+.

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 714
    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 714
    Par défaut
    Salut,

    Ces données proviennent des fichiers NOAA (une sorte de météo france pour les USA).
    Ces fichiers sont à format fixe et de a forme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    STN--- WBAN   YEARMODA    TEMP       DEWP      SLP        STP       VISIB      WDSP     MXSPD   GUST    MAX     MIN   PRCP   SNDP   FRSHTT 
    724940 23234  19730101    49.6 24    28.4 24  1024.5 24  1023.8 24   27.6 24    5.3 24   14.0   20.0    57.2*   37.4*  3.54G 999.9  000000 
    724940 23234  19740101    44.1 24    34.8 24  1012.6 24  1011.9 24   23.0 24    9.0 24   17.1   19.8    51.8*   37.4*  0.20G 999.9  110000 
    724940 23234  19750101    43.5 24    26.6 24  1026.9 24  1026.1 24   22.2 24    4.2 24   10.1  999.9    55.9*   34.0* 99.99G 999.9  010000 
    724940 23234  19760101    45.8 24    21.7 23  1019.1 24  1018.4 24   33.6 24   10.0 24   16.9  999.9    53.1*   39.9*  0.00I 999.9  000000
    Ce format est documenté par la NOAA ici. Pour les informations qui nous intéressent, on a:
    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
    ...
    YEAR    15-18     Int.   The year.
     
    MODA    19-22     Int.   The month and day.
    ...
    PRCP    119-123   Real   Total precipitation (rain and/or melted
                             snow) reported during the day in inches
                             and hundredths; will usually not end 
                             with the midnight observation--i.e., 
                             may include latter part of previous day.
                             .00 indicates no measurable              
                             precipitation (includes a trace).        
                             Missing = 99.99
                             Note:  Many stations do not report '0' on
                             days with no precipitation--therefore,  
                             '99.99' will often appear on these days.
                             Also, for example, a station may only
                             report a 6-hour amount for the period 
                             during which rain fell.
                             See Flag field for source of data.
    Et pour extraire cela d'une ligne écrite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> line
    '724940 23234  19730101    49.6 24    28.4 24  1024.5 24  1023.8 24   27.6 24    5.3 24   14.0   20.0    57.2*   37.4*  3.54G 999.9
     000000 '
    >>>
    On peut utiliser les positions données dans la documentation (en se rappelant que c'est un indexage "fortran"):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> line[15-1:22] # YEAR + MODA
    '19730101'
    >>> line[119-1:123] # PRCP
    ' 3.54'
    >>>
    De fait, les regexp n'apportent ici pas grand chose.

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

  5. #5
    Membre confirmé
    Inscrit en
    Novembre 2010
    Messages
    176
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 176
    Par défaut
    Bonsoir. Merci pour votre aide.

    Well .... le 'problème' venait surtout de ma façon de raisonner.

    J'avais en tête de rechercher les substrings du type 12345678 et 1.23A puis d'effacer tout le reste:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    re.sub(négation de ma pattern, remplacer par rien, sur ma longue string)
    .

    Ce qui est un peu compliqué ('tordu', en fait ...) . Il suffit d'utiliser la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    re.findall(ma pattern, sur ma longue string)
    . Et point barre.

    Merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Regex avec une négation
    Par rj450 dans le forum C#
    Réponses: 2
    Dernier message: 12/11/2013, 12h11
  2. [jakarta][regex]Matcher mot en entier.
    Par thibaut dans le forum Collection et Stream
    Réponses: 6
    Dernier message: 26/05/2004, 13h33
  3. [Regex] Vérifier qu'une chaîne respecte une expression régulière
    Par PeteMitchell dans le forum Collection et Stream
    Réponses: 7
    Dernier message: 13/05/2004, 14h22
  4. [regex][string] replaceAll bogué ?
    Par 7eme dans le forum Collection et Stream
    Réponses: 4
    Dernier message: 13/11/2003, 16h36
  5. Cherche regex...
    Par laurent_h dans le forum C
    Réponses: 4
    Dernier message: 31/03/2003, 11h24

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