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 :

Expression reguliere sur n lignes


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 12
    Par défaut Expression reguliere sur n lignes
    Bonsoir ,

    Je souhaiterais effectuer un contrôle syntaxique via les expressions régulières sur une variable de n lignes.

    pex :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def maFonction(field, format):
     	valide=True
    	if re.match(format,field):
    		valide=True
    	else:
    		valide=False
    	return valide
     
    champ="Bonjours\na\ntous"
    format="[a-zA-Z]"
    maFonction(champ,format)
    Je souhaiterai pouvoir via cette fonction écrire une expression régulière qui me permette d'effectuer un contrôle de syntaxe sur tous les mots de la chaine.

    Merci de votre contribution

    Lagdu

  2. #2
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Quel genre de contrôle syntaxique ?
    Le code que tu donnes (en supposant que maFonction est en fait check_field_format) va seulement vérifier que le premier caractère de la chaîne est une lettre, rien de plus.

    Comme tu parles de faire un contrôle sur tous les mots de la chaîne, si tu travailles mot par mot, tu peux pas simplement faire un split() et contrôler chaque mot ?

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 12
    Par défaut
    Salut divedee ,

    En fait le type de contrôle syntaxique est peut important. Le problème auquel je fait face est que :

    J'ai écris plusieurs expressions régulières pour faire un contrôle sur de chaines de caractères.

    Ses chaines de caractères sont généralement écrites sur une ligne, mais quelques une sont écrites sur 1 a n lignes.

    Concrètement je doit par exemple vérifier qu'une chaine comporte:
    4 caractères en majuscule puis deux slashs puis une valeur décimale de 10 caractères maximum deux slash puis éventuellement 5 lignes supplémentaires de 0 a 35 caractères.
    Ce qui me donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ("([A-Z]{4})//([0-9,]{10}//([a-zA-Z0-9/-?:().,'+{} ]{0,35})$")
    Malheureusement je ne sais pas comment exprimer le fait que la dernière partie puisse être écrite sur 1 à n lignes.

    Tu viens de me mettre sur une piste en utilisant éventuellement un split() , mais je souhaitais si possible me restreindre a l'utilisation d'expression régulière pour m'éviter d'alourdir mes traitements sur les chaines.

    J'espère avoir été plus clair dans mes explications.

    PS : effectivement je me suis trompé de nom lors de l'appel de la fonction . C'est bien maFonction(champ,format) qui est appelée j'édite le message précédent.

  4. #4
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Quelqu'un connaissant mieux les expressions régulières passera peut-être, mais en attendant, as-tu essayé qqch comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    "([A-Z]{4})//([0-9,]{10}//(([a-zA-Z0-9/-?:().,'+{} ]{0,35})\n){0,5}$"
    Regarde aussi l'option MULTILINE, qui change la signification de $.
    Mais si les données contiennent plusieurs fois le motif, cela risque de poser un problème, car la deuxième partie du motif:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ([a-zA-Z0-9/-?:().,'+{} ]{0,35})
    matche aussi le début d'une nouvelle apparition du motif:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ([A-Z]{4})//([0-9,]{10}//
    Toute chaîne correspondant à la première partie du motif correspond également à la seconde. Il faut qu'il y ait un moyen de distinguer une ligne supplémentaire de l'instance courante du motif avec le début d'une nouvelle instance du motif.

  5. #5
    Membre Expert
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Par défaut
    Maintenant que tu as précisé ta demande, on peut essayer d'y répondre.
    Mais ça ne m'a pas empêché de m'intéresser au sujet. Je l'ai étudié un peu en me disant qu'à défaut de pouvoir donner une réponse à une question mal posée, je pouvais essayer de trouver les questions possibles sur le sujet...
    Alors voilà le fruit de mes cogitations.


    J'ai d'abord vérifié qu'effectivement on peut examiner par regex une chaine comportant des caractères '\n':

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    fruits = \
    'noix,noisette\nbanane,citron\ngroseille,fraise,framboise\ncassis,\
    mûre\nlitchi,avocat,goyave\n'
    print 'recherche1 =',[re.search('.*fraise.*\n.*cassis.*',fruits).group()]
    donne
    recherche1 = ['groseille,fraise,framboise\ncassis,m\xfbre']
    NB: les crochets autour de re.search(...).group() permettent d'avoir un affichage de tous les caractères y compris les caractères spéciaux comme '\n' et '\xfb' et non pas de les faire jouer en tant que caractères spéciaux.

    On voit que '.*' devant 'fraise' fait prendre en compte les caractères devant 'fraise' par la regex mais qu'elle ne prend pas ceux avant '\n' parce que le point '.' ne matche pas avec '\n'. Sauf si on écrit explicitement '\n' dans la regex.
    Documentation:
    «Dans le mode par défaut, '.' matche n'importe quel caractère sauf un newline. Si le drapeau DOTALL est spécifié, le point '.' matche tous les caractères y compris les newline.»

    Et en effet:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    fruits = \
    'noix,noisette\nbanane,citron\ngroseille,fraise,framboise\ncassis,\
    mûre\nlitchi,avocat,goyave\n'
    print 'recherche2 =',[re.search('.*fraise.*\n.*cassis.*',fruits,re.DOTALL).group()]
    donne
    recherche2 = ['noix,noisette\nbanane,citron\ngroseille,fraise,framboise\ncassis,m\xfbre\nlitchi,avocat,goyave\n']
    -----------------------------------------------------------------------

    Ensuite, j'ai regardé des trucs un peu plus compliqués.

    Question 1: peut on par exemple, avec les regex, extraire d'un fichier les lignes comportant un certain motif mais sans examiner explicitement les lignes l'une après l'autre avec un for ligne in fichier:, et sans mettre non plus le fichier en liste ? C'est à dire d'appliquer un algorithme de regex sur le fichier considéré sous sa forme native de chaine de caractères.


    Pour une recherche simple, le for ligne in f est le plus simple. Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    fruits = 'noix,noisette\nbanane,citron\ngroseille,fraise,framboise\n\
    cassis,mûre\nlitchi,avocat,goyave\n'
    f = open('fichier fruits','w')
    f.write(fruits)
    f.close()
     
    f = open('fichier fruits')
    lignes = [ln for ln in f if 'a' in ln]
    f.close()
    print 'lignes de fruits avec a =\n',lignes
    donne
    lignes de fruits avec a =
    ['banane,citron\n', 'groseille,fraise,framboise\n', 'cassis,m\xfbre\n', 'litchi,avocat,goyave\n']
    ou bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    f = open('fichier fruits')
    lignes = [ln for ln in f if 'goyave' in ln]
    f.close()
    print 'lignes de fruits avec goyave =',lignes
    donne
    lignes de fruits avec goyave =
    ['litchi,avocat,goyave\n']



    Mais dès que c'est un peu plus compliqué ,c'est moins simple (si, si):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    f = open('fichier fruits')
    lignes = [ln for ln in f if set(['fraise','cassis']).intersection(set(ln.split(',')))!=set([])]
    f.close()
    print 'lignes fraises-cassis =',lignes
    donne bien
    lignes fraise-cassis =
    ['groseille,fraise,framboise\n', 'cassis,m\xfbre\n']




    Pour ce qui suit, on est obligé d'abandonner le recours à une list comprehension:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    f = open('fichier fruits')
    selec = []
    for ln in f:
        for mot in ln.split(','):
            if 'a' in mot and 'o' in mot:
                selec.append(ln)
                break
    f.close()
    print "\nlignes avec mots contenant a la fois'o' et 'a' au moyen de for ln in f: et d'un if ="
    print selec
    donne
    lignes avec mots contenant a la fois'o' et 'a' au moyen de for ln in f: et d'un if =
    ['groseille,fraise,framboise\n', 'litchi,avocat,goyave\n']
    Si on utilise une list comprehension, on ne peut pas mettre le break (en tous cas je ne sais pas le faire; si quelqu'un sait comment procéder, je suis intéressé) qui est nécessaire pour éviter de sélectionner deux fois des lignes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    f = open('fichier fruits')
    soloc = [ln for ln in f for mot in ln.split(',') if ('a' in mot and 'o' in mot)]
    f.close()
    print "\nlignes avec mots contenant a la fois'o' et 'a' (incorrecte)"
    print "au moyen de for ln in f: et d'un if dans une list comprehension ="
    print soloc
    donne
    lignes avec mots contenant a la fois'o' et 'a' (incorrecte)
    au moyen de for ln in f: et d'un if dans une list comprehension =
    ['groseille,fraise,framboise\n', 'litchi,avocat,goyave\n', 'litchi,avocat,goyave\n']


    Avec une regex, c'est déjà plus condensé et exact, même si ça ne parait pas plus simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    f = open('fichier fruits')
    silic = []
    for ln in f:
        if re.search('(^|,)[a-z]*((a[a-z]+o)|(o[a-z]+a))[a-z]*(,|$)',ln):
            silic.append(ln)
    f.close()
    print "\nlignes avec mots contenant a la fois 'o' et 'a' au moyen de for ln in f: et d'une regex ="
    print silic
    donne bien aussi
    lignes avec mots contenant a la fois 'o' et 'a' au moyen de for ln in f: et d'une regex =
    ['groseille,fraise,framboise\n', 'litchi,avocat,goyave\n']
    NB: ici les signes '^' et '$' matchent le début et la fin de chaque ligne.




    Si on fait appel à toutes les possibilités des regex, c'est à dire cette fois à finditer() , ça devient aussi simple qu'une list comprehension:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    f = open('fichier fruits')
    print "\nlignes avec mots contenant a la fois 'o' et 'a' au moyen de la fonction finditer() ="
    print [m.group() for m in re.finditer('^([a-z]+,)*[a-z]*((a[a-z]+o)|(o[a-z]+a))[a-z]*(,[a-z]+)*$',f.read(),re.M)]
    f.close()
    donne
    lignes avec mots contenant a la fois 'o' et 'a' au moyen de la fonction finditer() =
    ['groseille,fraise,framboise', 'litchi,avocat,goyave']
    >>>
    On obtient même les lignes sans le caractères line break '\n' terminal.

    NB: du fait que finditer() est utilisé au lieu de search(), la regex doit être différente pour que le matching se fasse sur la totalité d'une "ligne" afin que la chaine qui matche, donnée par m.group() , soit cette "ligne" et non pas seulement le mot avec 'o' et 'a' qui fait l'essentiel du matching.
    NB2: finditer() n'examine pas des lignes, il examine une chaine f.read() d'un seul bloc dans laquelle les signes '^' et '$' permettent de repérer le début et la fin de chacune des portions qui donnent les lignes lors d'un affichage de f.read(). Pour que '^' et '$' matchent avec "juste après '\n'" et "juste avant '\n'" , il faut ajouter le drapeau re.MULTILINE comme argument de la fonction finditer(). Il oblige "^" et "$" à matcher autour de '\n' et pas seulement aux extrémités d'une chaine.


    -------------------------------------------------

    Deuxième question: comment se passent les détections par regex sur plusieurs lignes ? C'est à dire comment se passent les choses pour des cas plus sophistiqués que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    re.search('.*fraise.*\n.*cassis.*','noix,noisette\nbanane,citron\n\
    groseille,fraise,framboise\ncassis,mûre\nlitchi,avocat,goyave\n') ?
    J'ai résumé des choses dans le code suivant

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    import re
     
    f = open('fifi','w')
    f.write('oceans\t\t\t361126222 km2\n')
    f.write('ocean pacifique\t\t166241700 km2\n')
    f.write('terres emergees\t\t148939063 km2\n')
    f.write('ocean atlantique\t106000000 km2\n')
    f.write('ocean indien\t\t75000000 km2\n')
    f.write('asie\t\t\tt43810582 km2\n')
    f.write('amerique\t\t42189120 km2\n')
    f.write('afrique\t\t\t30206704 km2\n')
    f.write('ocean antarctique\t20327000 km2\n')
    f.write('antarctique\t\t14200000 km2\n')
    f.write('ocean arctique\t\t14090000 km2\n')
    f.write('europe\t\t\t10180000 km2\n')
    f.close()
     
     
    f = open('fifi','r')
    ch = f.read()
    f.close()
    print '---------------------------------------1'
    for m in re.finditer('^ocean.+ique',ch):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+ique',ch):
        print [m.group()]
    print '---------------------------------------2'
    for m in re.finditer('^ocean.+ique',ch,re.S):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+ique',ch,re.S):
        print [m.group()]
    print '---------------------------------------3'
    for m in re.finditer('^ocean.+ique',ch,re.M):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+ique',ch,re.M):
        print [m.group()]
    print '---------------------------------------4'
    for m in re.finditer('^ocean.+ique',ch,re.M|re.S):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+ique',ch,re.M|re.S):
        print [m.group()]
    print '\n'
    print '---------------------------------------5'
    for m in re.finditer('^ocean.+?ique',ch,re.S):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+?ique',ch,re.S):
        print [m.group()]
    print '---------------------------------------6'
    for m in re.finditer('^ocean.+?ique',ch,re.M):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+?ique',ch,re.M):
        print [m.group()]
    print '---------------------------------------7'
    for m in re.finditer('^ocean.+?ique',ch,re.M|re.S):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+?ique',ch,re.M|re.S):
        print [m.group()]
     
    print '---------------------------------------8'
    for m in re.finditer('^ocean.+(ique)?',ch):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+(ique)?',ch):
        print [m.group()]
    print '---------------------------------------9'
    for m in re.finditer('^ocean.+(ique)?',ch,re.M):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+(ique)?',ch,re.M):
        print [m.group()]
    print '---------------------------------------10'
    for m in re.finditer('^ocean.+?(ique)?',ch,re.M):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+?(ique)?',ch,re.M):
        print [m.group()]
    print '---------------------------------------11'
    for m in re.finditer('^ocean.+?(ique)?$',ch,re.M):
        print 'AAAA'+m.group()+'ZZZZ'
    for m in re.finditer('^ocean.+?(ique)?$',ch,re.M):
        print [m.group()]
    print '---------------------------------------'
    qui donne
    ---------------------------------------1
    pattern = ^ocean.+ique
    ---------------------------------------2
    pattern = ^ocean.+ique
    AAAAoceans 361126222 km2
    ocean pacifique 166241700 km2
    terres emergees 148939063 km2
    ocean atlantique 106000000 km2
    ocean indien 75000000 km2
    asie t43810582 km2
    amerique 42189120 km2
    afrique 30206704 km2
    ocean antarctique 20327000 km2
    antarctique 14200000 km2
    ocean arctiqueZZZZ
    ['oceans\t\t\t361126222 km2\nocean pacifique\t\t166241700 km2\nterres emergees\t\t148939063 km2\nocean atlantique\t106000000 km2\nocean indien\t\t75000000 km2\nasie\t\t\tt43810582 km2\namerique\t\t42189120 km2\nafrique\t\t\t30206704 km2\nocean antarctique\t20327000 km2\nantarctique\t\t14200000 km2\nocean arctique']
    ---------------------------------------3
    pattern = ^ocean.+ique
    AAAAocean pacifiqueZZZZ
    AAAAocean atlantiqueZZZZ
    AAAAocean antarctiqueZZZZ
    AAAAocean arctiqueZZZZ
    ['ocean pacifique']
    ['ocean atlantique']
    ['ocean antarctique']
    ['ocean arctique']
    ---------------------------------------4
    pattern = ^ocean.+ique
    AAAAoceans 361126222 km2
    ocean pacifique 166241700 km2
    terres emergees 148939063 km2
    ocean atlantique 106000000 km2
    ocean indien 75000000 km2
    asie t43810582 km2
    amerique 42189120 km2
    afrique 30206704 km2
    ocean antarctique 20327000 km2
    antarctique 14200000 km2
    ocean arctiqueZZZZ
    ['oceans\t\t\t361126222 km2\nocean pacifique\t\t166241700 km2\nterres emergees\t\t148939063 km2\nocean atlantique\t106000000 km2\nocean indien\t\t75000000 km2\nasie\t\t\tt43810582 km2\namerique\t\t42189120 km2\nafrique\t\t\t30206704 km2\nocean antarctique\t20327000 km2\nantarctique\t\t14200000 km2\nocean arctique']


    ---------------------------------------5
    pattern = ^ocean.+?ique
    AAAAoceans 361126222 km2
    ocean pacifiqueZZZZ
    ['oceans\t\t\t361126222 km2\nocean pacifique']
    ---------------------------------------6
    pattern = ^ocean.+?ique
    AAAAocean pacifiqueZZZZ
    AAAAocean atlantiqueZZZZ
    AAAAocean antarctiqueZZZZ
    AAAAocean arctiqueZZZZ
    ['ocean pacifique']
    ['ocean atlantique']
    ['ocean antarctique']
    ['ocean arctique']
    ---------------------------------------7
    pattern = ^ocean.+?ique
    AAAAoceans 361126222 km2
    ocean pacifiqueZZZZ
    AAAAocean atlantiqueZZZZ
    AAAAocean indien 75000000 km2
    asie t43810582 km2
    ameriqueZZZZ
    AAAAocean antarctiqueZZZZ
    AAAAocean arctiqueZZZZ
    ['oceans\t\t\t361126222 km2\nocean pacifique']
    ['ocean atlantique']
    ['ocean indien\t\t75000000 km2\nasie\t\t\tt43810582 km2\namerique']
    ['ocean antarctique']
    ['ocean arctique']
    ---------------------------------------8
    pattern = ^ocean.+(ique)?
    AAAAoceans 361126222 km2ZZZZ
    ['oceans\t\t\t361126222 km2']
    ---------------------------------------9
    pattern = ^ocean.+(ique)?
    AAAAoceans 361126222 km2ZZZZ
    AAAAocean pacifique 166241700 km2ZZZZ
    AAAAocean atlantique 106000000 km2ZZZZ
    AAAAocean indien 75000000 km2ZZZZ
    AAAAocean antarctique 20327000 km2ZZZZ
    AAAAocean arctique 14090000 km2ZZZZ
    ['oceans\t\t\t361126222 km2']
    ['ocean pacifique\t\t166241700 km2']
    ['ocean atlantique\t106000000 km2']
    ['ocean indien\t\t75000000 km2']
    ['ocean antarctique\t20327000 km2']
    ['ocean arctique\t\t14090000 km2']
    ---------------------------------------10
    pattern = ^ocean.+?(ique)?
    AAAAoceansZZZZ
    AAAAocean ZZZZ
    AAAAocean ZZZZ
    AAAAocean ZZZZ
    AAAAocean ZZZZ
    AAAAocean ZZZZ
    ['oceans']
    ['ocean ']
    ['ocean ']
    ['ocean ']
    ['ocean ']
    ['ocean ']
    ---------------------------------------11
    pattern = ^ocean.+?(ique)?$
    AAAAoceans 361126222 km2ZZZZ
    AAAAocean pacifique 166241700 km2ZZZZ
    AAAAocean atlantique 106000000 km2ZZZZ
    AAAAocean indien 75000000 km2ZZZZ
    AAAAocean antarctique 20327000 km2ZZZZ
    AAAAocean arctique 14090000 km2ZZZZ
    ['oceans\t\t\t361126222 km2']
    ['ocean pacifique\t\t166241700 km2']
    ['ocean atlantique\t106000000 km2']
    ['ocean indien\t\t75000000 km2']
    ['ocean antarctique\t20327000 km2']
    ['ocean arctique\t\t14090000 km2']
    ---------------------------------------
    Cas 1:
    '^' matche uniquement le début de ch.
    le point ne matche pas avec '\n'.
    '^ocean.+ique' commence au début de ch et s'arrête avant le premier '\n'. Comme il n'y a pas la sous-chaine 'ique' requise dans la portion 'oceans\t\t\t361126222 km2\' , la regex ne matche rien.

    Cas 2:
    '^' matche uniquement le début de ch.
    La présence du drapeau re.S force le point à matcher avec les newlines '\n'.
    Comme '+' est glouton ( documentation: «The "*", "+", and "?" qualifiers are all greedy; they match as much text as possible.»), la RE '.+' va aussi loin que possible avant de s'arrêter devant une succession 'ique' qui est requise: '.+' va donc jusqu'au 'ique' de l'avant-dernière ligne. Même les lignes qui ne contiennent pas 'ique' sont aussi prises dans le match.
    D'ailleurs, comme '.+' s'arrête au dernier 'ique', la superficie de cette ligne n'est pas dans la chaine matchée: il y a un hic.

    Cas 3:
    Comme en 1, la regex ne matche toujours rien dans la première portion allant du début de ch au premier '\n'.
    Comme il n'y a pas de drapeau re.S (abbréviation de re.DOTALL), le point dans '.+' ne matche pas avec le premier newline '\n' et empêche la regex d'explorer au delà du premier newline.
    Cependant la présence du drapeau re.M fait matcher '^' au début de ch et juste après tous les '\n'. Donc re.M permet à '^' d'explorer la suite, et il y a détection des portions comprises entre tous les '\n' suivants, ce qui correspond aux lignes, et la regex matche quand il y a 'ique'.

    Cas 4:
    c'est le cas 2 + cas 3 additionnés: le caractère glouton de '.+' rend inopérante la faculté de '^' de matcher après les newlines. La regex va d'abord jusqu'au dernier 'ique', requis, puis '^' fait explorer la dernière ligne dans laquelle il n'y a pas de 'ique'.
    Le réultat est le mêm que dans le cas 2.

    Cas 5:
    si on rend '.+' non glouton en modifiant son comportement par un '?' (documentation: «Adding "?" after the qualifier makes it perform the match in non-greedy or minimal fashion; as few characters as possible will be matched.» il s'agit de *?, +?, ?? ), la regex consomme la chaine seulement tant qu'elle ne rencontre pas le premier 'ique'. Comme re.S permet au point de passer le premier '\n', la regex peut aller jusqu'au 'ique' de la deuxième ligne. Elle matche donc du début de la première ligne qui ne contient pourtant pas de 'ique' jusqu'au 'ique' de la deuxième ligne.
    Comme il n'y a pas de re.M pour autoriser '^' à matcher aprés le deuxième '\n', la regex n'explore pas plus loin.

    Cas 6:
    '.+' est rendu frugal par '?', ce qui ne change strictement rien par rapport au cas 3: l'absence de drapeau re.S empêche la regex d'explorer au delà du premier newline.
    Mais comme en 3, re.M permet à la regex d'explorer toutes les lignes.
    Le résultat est donc identique au cas 3.

    Cas 7:
    C'est le cas 4 + '.+?' rendu frugal.
    - '.+?' grignote la chaine, en passant les '\n' gràce à re.S, jusqu'à rencontrer un 'ique' requis
    C'est ainsi que les lignes sans 'ique' comme 'oceans\t\t\t361126222 km2\n' , 'ocean indien\t\t75000000 km2\n' , 'asie\t\t\tt43810582 km2\n' , 'amerique\t\t42189120 km2\n' qui sont parcourues par le grignotage participent aux résultats.
    - Par contre '^ocean' et re.M permettent à la regex d'explorer toutes les portions commençant par 'ocean' après '\n', et les lignes 'terres emergees\t\t148939063 km2\n' , 'afrique\t\t\t30206704 km2\n' , 'antarctique\t\t14200000 km2\n' et 'europe\t\t\t10180000 km2\n' sont exclues des portions matchantes.

    Cas 8:
    La regex part du début de la chaine et bute sur le premier '\n' mais le (ique)? est facultatif. À la différence du cas 1, l e résultat est donc la première ligne.

    Cas 9:
    La regex part de chaque début de ligne commençant par 'ocean', car re.M permet à '^' de matcher après chaque newline et à la regex d'explorer tout le fichier.
    (ique)? est facultatif mais '.+' ne bute que sur le premier '\n' rencontré. Le résultat est donc formé de toutes les lignes commençant par 'ocean', dans leur entier.

    Cas 10:
    (ique)? est facultatif et la RE '.+?' est '.+' rendue flemmarde par '?'
    '.+?' s'arrête donc 1 caractère après 'ocean', c'est à dire dès qu'il a trouvé le caractère obligatoire spécifié par '+'.

    Cas 11:
    C'est un cas intéressant à examiner.
    C'est le cas 10 auquel on a juste ajouté le caractère '$' qui matche juste avant les '\n'. Sa présence oblige '.+?' à parcourir des caractères jusqu'à rencontrer un newline '\n'. On peut noter que la regex passe dessus 'ique' grâce à '.+?' et non grâce à (ique)?, sinon '.+?' ne pourrait pas continuer pour les caractères situés au delà de 'ique'.
    Le cas 10 se trouve modulé et on se retrouve avec comme résultat l'ensemble des lignes entières contenant 'ocean'.

    Bon, on peut s'amuser comme ça à l'infini.

    -----------------------------------------------------------------

    Troisième question: y a-t-il d'autres avantages que la concision à utiliser les regex et finditer() au lieu d'une boucle sur un fichier ?

    Il y a au moins la vitesse, le recours à finditer() en list comprehension a tendance à être 28% plus rapide que les autres méthodes:

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    import re
    from timeit import Timer
     
    f = open('fifi','w')
    f.write('oceans\t\t\t361126222 km2\n')
    f.write('ocean pacifique\t\t166241700 km2\n')
    f.write('terres emergees\t\t148939063 km2\n')
    f.write('ocean atlantique\t106000000 km2\n')
    f.write('ocean indien\t\t75000000 km2\n')
    f.write('asie\t\t\tt43810582 km2\n')
    f.write('amerique\t\t42189120 km2\n')
    f.write('afrique\t\t\t30206704 km2\n')
    f.write('ocean antarctique\t20327000 km2\n')
    f.write('antarctique\t\t14200000 km2\n')
    f.write('ocean arctique\t\t14090000 km2\n')
    f.write('europe\t\t\t10180000 km2\n')
    f.close()
     
    def simpl():
        f = open('fifi','r')
        fh = f.readlines()
        f.close()
        loo = []
        for ln in fh:
            if re.search('^ocean.+$',ln):
                loo.append(ln)
        return loo
     
    def litfh():
        f = open('fifi','r')
        fh = f.readlines()
        f.close()
        return [ ln for ln in fh if re.search('^ocean.+$',ln) ]
     
    def diter():
        f = open('fifi','r')
        ch = f.read()
        f.close()
        return [ m.group() for m in re.finditer('^ocean.+$',ch,re.M) ]
     
    iterations = 12
    tsimpl = Timer('simpl()','from __main__ import simpl').repeat(iterations, 1000)
    tlitfh = Timer('litfh()','from __main__ import litfh').repeat(iterations, 1000)
    tditer = Timer('diter()','from __main__ import diter').repeat(iterations, 1000)
     
    print simpl()
    print "avec if re.search('^ocean.+$',ln): loo.append(ln)"
    for u in tsimpl:
        print round(u,4),
    print '  secondes'
    print 'moyenne = ',round(sum(tsimpl)/iterations,4)
    print '\n'
    print litfh()
    print "avec [ ln for ln in fh if re.search('^ocean.+$',ln) ]"
    for u in tlitfh:
        print round(u,4),
    print '  secondes'
    print 'moyenne = ',round(sum(tlitfh)/iterations,4)
    print '\n'
    print diter()
    print "avec [ m.group() for m in re.finditer('^ocean.+$',ch,re.M) ]"
    for u in tditer:
        print round(u,4),
    print '  secondes'
    print 'moyenne = ',round(sum(tditer)/iterations,4)
    print '\n'
    ['oceans\t\t\t361126222 km2\n', 'ocean pacifique\t\t166241700 km2\n', 'ocean atlantique\t106000000 km2\n', 'ocean indien\t\t75000000 km2\n', 'ocean antarctique\t20327000 km2\n', 'ocean arctique\t\t14090000 km2\n']
    avec if re.search('^ocean.+$',ln): loo.append(ln)
    0.5868 0.5768 0.6136 0.7969 0.5868 0.6043 0.61 0.6453 0.7049 0.5889 0.5814 0.5797 secondes
    moyenne = 0.6229


    ['oceans\t\t\t361126222 km2\n', 'ocean pacifique\t\t166241700 km2\n', 'ocean atlantique\t106000000 km2\n', 'ocean indien\t\t75000000 km2\n', 'ocean antarctique\t20327000 km2\n', 'ocean arctique\t\t14090000 km2\n']
    avec [ ln for ln in fh if re.search('^ocean.+$',ln) ]
    0.5778 0.6064 0.5801 0.5754 0.7579 0.5729 0.582 0.5908 0.581 0.5888 0.5772 0.5764 secondes
    moyenne = 0.5972


    ['oceans\t\t\t361126222 km2', 'ocean pacifique\t\t166241700 km2', 'ocean atlantique\t106000000 km2', 'ocean indien\t\t75000000 km2', 'ocean antarctique\t20327000 km2', 'ocean arctique\t\t14090000 km2']
    avec [ m.group() for m in re.finditer('^ocean.+$',ch,re.M) ]
    0.4703 0.5238 0.4036 0.4032 0.4028 0.4059 0.4052 0.4019 0.404 0.4035 0.4057 0.4025 secondes
    moyenne = 0.4194
    -------------------------------------------------

    Quatrième question: différences d'usage entre '^' , '$' et '\n' dans une regex.

    '^' et '$' sont bivalents tandis que '\n' est rarement présent en tête de fichier, '\n' est diversement présent à la fin d'un fichier et '\A' et '\Z' ne s'appliquent qu'aux extrémités d'un string.
    '^' et '$' sont donc plus pratiques que (\n|\A) et (\n|\Z).
    Si '$' n'existait pas, (\n|\Z) serait indispensable dans toutes le regex destinées à détecter des lignes dans une chaine.

    Si par exemple on veut vérifier que toutes les lignes d'un fichier commencent par un nom d'océan contenant la lettre 'i':

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    import re
     
     
    f = open('fifi','w')
    f.write('tous les oceans existants\t361126222 km2\n')
    f.write('ocean pacifique\t\t\t166241700 km2\n')
    f.write('ocean atlantique\t\t106000000 km2\n')
    f.write('ocean indien\t\t\t75000000 km2\n')
    f.write('ocean antarctique\t\t20327000 km2\n')
    f.write('ocean arctique\t\t\t14090000 km2')
    f.close()
     
    f = open('fifi','r')
    ch = f.read()
    f.close()
    print '[ch] =\n',[ch]
    print '\nch =\n',ch
    print
    print '================================================================================'
     
    pat = "ocean.+i.+(\Z|\n)"
    for m in re.finditer(pat,ch):
        print m.group()
    for m in re.finditer(pat,ch):
        print [m.group()]
    print '-----------------------------------------'
    pat = "(\A|\n)ocean.+i.+(\Z|\n)"
    for m in re.finditer(pat,ch):
        print m.group()
    for m in re.finditer(pat,ch):
        print [m.group()]
    print '-----------------------------------------'
    pat = '^ocean.+i.+$'
    for m in re.finditer(pat,ch,re.M):
        print m.group()
    for m in re.finditer(pat,ch,re.M):
        print [m.group()]
    print '-----------------------------------------'
    [ch] =
    ['tous les oceans existants\t361126222 km2\nocean pacifique\t\t\t166241700 km2\nocean atlantique\t\t106000000 km2\nocean indien\t\t\t75000000 km2\nocean antarctique\t\t20327000 km2\nocean arctique\t\t\t14090000 km2']

    ch =
    tous les oceans existants 361126222 km2
    ocean pacifique 166241700 km2
    ocean atlantique 106000000 km2
    ocean indien 75000000 km2
    ocean antarctique 20327000 km2
    ocean arctique 14090000 km2

    ================================================================================
    oceans existants 361126222 km2

    ocean pacifique 166241700 km2

    ocean atlantique 106000000 km2

    ocean indien 75000000 km2

    ocean antarctique 20327000 km2

    ocean arctique 14090000 km2
    ['oceans existants\t361126222 km2\n']
    ['ocean pacifique\t\t\t166241700 km2\n']
    ['ocean atlantique\t\t106000000 km2\n']
    ['ocean indien\t\t\t75000000 km2\n']
    ['ocean antarctique\t\t20327000 km2\n']
    ['ocean arctique\t\t\t14090000 km2']
    -----------------------------------------

    ocean pacifique 166241700 km2


    ocean indien 75000000 km2


    ocean arctique 14090000 km2
    ['\nocean pacifique\t\t\t166241700 km2\n']
    ['\nocean indien\t\t\t75000000 km2\n']
    ['\nocean arctique\t\t\t14090000 km2']
    -----------------------------------------
    ocean pacifique 166241700 km2
    ocean atlantique 106000000 km2
    ocean indien 75000000 km2
    ocean antarctique 20327000 km2
    ocean arctique 14090000 km2
    ['ocean pacifique\t\t\t166241700 km2']
    ['ocean atlantique\t\t106000000 km2']
    ['ocean indien\t\t\t75000000 km2']
    ['ocean antarctique\t\t20327000 km2']
    ['ocean arctique\t\t\t14090000 km2']
    -----------------------------------------
    Le pattern "ocean.+i.+(\Z|\n)" fait trouver la première ligne OK alors qu'elle ne l'est pas.
    Si on cherche à ajouter (\A|\n) dans la regex pour éliminer cette erreur (deuxième pattern "(\A|\n)ocean.+i.+(\Z|\n)" ), alors il apparait une autre erreur:
    une fois qu'un '\n' est consommé par (\Z|\n) , il n'est plus disponible pour (\A|\n) dans l'examen de la ligne suivante, ce qui fait que l'examen saute la détection des lignes 'ocean atlantique\t\t106000000 km2\n' et 'ocean antarctique\t\t20327000 km2\n'.
    Le troisiéme pattern '^ocean.+i.+$' donne satisfaction.
    De plus l'usage de '^' et '$' permet aussi de se retrouver avec des lignes propres, sans '\n'.

  6. #6
    Membre Expert
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Par défaut
    -----------------------------------------------------------

    Cinquième question: peut faire d'un seul coup avec une regex une vérification de l'ensemble des lignes d'un fichier, sans faire de for ligne in fichier: ou de mise en liste ?

    Yes.
    D'abord il faut utiliser match() pour faire une détection à partir du début du fichier.

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    import re
     
    f = open('fifi','w')
    f.write('tous les oceans existan\t\t361126222 km2\n')
    f.write('ocean pacifique\t\t166241700 km2\n')
    f.write('ocean atlantique\t106000000 km2\n')
    f.write('ocean indien\t\t75000000 km2\n')
    f.write('ocean antarctique\t20327000 km2\n')
    f.write('ocean arctique\t\t14090000 km2')
    f.close()
     
    f = open('fifi','r')
    ch = f.read()
    f.close()
     
    print '-----------------------------------------'
    print '[ch] =\n',[ch],'\n'
    print 'avec pattern =',r'((^ocean.+ique)+)','\n'
    m = re.match('((^ocean.+ique)+)',ch,re.M)
    if m:
        print m.groups()
        print [m.group()]
        print '-- fichier OK --'
    else:
        print '>>>>>--  au moins une ligne non conforme  --<<<<<<<'
     
     
    f = open('fifi','w')
    f.write('ocean pacifique\t\t166241700 km2\n')
    f.write('ocean atlantique\t106000000 km2\n')
    f.write('ocean indien\t\t75000000 km2\n')
    f.write('ocean antarctique\t20327000 km2\n')
    f.write('ocean arctique\t\t14090000 km2')
    f.close()
     
    f = open('fifi','r')
    ch = f.read()
    f.close()
     
    print '-----------------------------------------'
    print '[ch] =\
    ttern =',r'((^ocean.+ique)+)','\n'
    m = re.match('((^ocean.+ique)+)',ch,re.M)
    if m:
        print m.groups()
        print [m.group()]
        print '-- fichier OK --'
    else:
        print '>>>>>--  au moins une ligne non conforme  --<<<<<<<'
    ----------------------------------------
    [ch] =
    ['tous les oceans existan\t\t361126222 km2\nocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean indien\t\t75000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2']

    avec pattern = ((^ocean.+ique)+)

    >>>>>-- au moins une ligne non conforme --<<<<<<<
    -----------------------------------------
    [ch] =ttern = ((^ocean.+ique)+)

    ('ocean pacifique', 'ocean pacifique')
    ['ocean pacifique']
    -- fichier OK --

    Dans le premier cas, la première ligne 'tous les oceans existan\t\t361126222 km2\n' fait foirer la vérification.
    Dans le deuxième cas, après avoir enlevé cette ligne, le fichier est trouvé OK mais c'est une illusion: en regardant ce que donnent print m.groups() et print [m.group()] , on voit que le match ne va que jusqu'à 'ocean pacifique' de la première ligne.

    Il faut modifier la regex parce qu'il est obligatoire que chaque ligne soit vérifiée dans son entier et que la liaison de toutes les lignes par (...)+ fasse bien une vérification de l'ensemble des lignes. Mais pour cela on est obligé de mettre '\n', sinon avec '$' la regex s'arrête avant le '\n' de la première ligne.

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    f = open('fifi','w')
    f.write('ocean pacifique\t\t166241700 km2\n')
    f.write('ocean atlantique\t106000000 km2\n')
    f.write('ocean indien\t\t75000000 km2\n')
    f.write('ocean antarctique\t20327000 km2\n')
    f.write('ocean arctique\t\t14090000 km2')
    f.close()
     
    f = open('fifi','r')
    ch = f.read()
    f.close()
     
    print '-----------------------------------------'
    print '[ch] =\n',[ch],'\n'
    print 'avec pattern =',r'((^ocean.+ique.+$)+)','\n'
    m = re.match('((^ocean.+ique.+$)+)',ch,re.M)
    if m:
        print m.groups()
        print [m.group()]
        print '-- fichier OK --'
    else:
        print '>>>>>--  au moins une ligne non conforme  --<<<<<<<'
     
     
     
    f = open('fifi','w')
    f.write('ocean pacifique\t\t166241700 km2\n')
    f.write('ocean atlantique\t106000000 km2\n')
    f.write('ocean indien\t\t75000000 km2\n')
    f.write('ocean antarctique\t20327000 km2\n')
    f.write('ocean arctique\t\t14090000 km2')
    f.close()
     
    f = open('fifi','r')
    ch = f.read()
    f.close()
     
    print '-----------------------------------------'
    print '[ch] =\n',[ch],'\n'
    print 'avec pattern =',r'((^ocean.+ique.+\n)+)','\n'
    m = re.match('((^ocean.+ique.+\n)+)',ch,re.M)
    if m:
        print m.groups()
        print [m.group(1)]
        print '-- fichier OK --'
    else:
        print '>>>>>--  au moins une ligne non conforme  --<<<<<<<'
    -----------------------------------------
    [ch] =
    ['ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean indien\t\t75000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2']

    avec pattern = ((^ocean.+ique.+$)+)

    ('ocean pacifique\t\t166241700 km2', 'ocean pacifique\t\t166241700 km2')
    ['ocean pacifique\t\t166241700 km2']
    -- fichier OK --
    -----------------------------------------
    [ch] =
    ['ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean indien\t\t75000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2']

    avec pattern = ((^ocean.+ique.+\n)+)

    ('ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\n', 'ocean atlantique\t106000000 km2\n')
    ['ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\n']
    -- fichier OK --
    Ce n'est pas suffisant: il y a un matching des deux premières lignes qui fait déclarer le fichier OK alors qu'il y a une ligne 'ocean indien\t\t75000000 km2\n' qui ne repecte pas ce qui est requis. Ce n'est pas un matching partiel qu'on veut. On veut que le matching commence au début de la chaine et soit valable jusqu'au bout de la chaine.
    Pour obtenir cela il faut ajouter '\Z'.
    Avec '\Z', on arrive bien cette fois à distinguer un fichier avec une mauvaise ligne d'un fichier entièrement correct:

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    f = open('fifi','w')
    f.write('ocean pacifique\t\t166241700 km2\n')
    f.write('ocean atlantique\t106000000 km2\n')
    f.write('ocean indien\t\t75000000 km2\n')
    f.write('ocean antarctique\t20327000 km2\n')
    f.write('ocean arctique\t\t14090000 km2\n')
    f.close()
     
    f = open('fifi','r')
    ch = f.read()
    f.close()
     
    print '-----------------------------------------'
    print '[ch] =\n',[ch],'\n'
    print 'avec pattern =',r'(((^ocean.+ique.+\n)+)\Z)','\n'
    m = re.match('(((^ocean.+ique.+\n)+)\Z)',ch,re.M)
    if m:
        print m.groups()
        print [m.group()]
        print '-- fichier OK --'
    else:
        print '>>>>>--  au moins une ligne non conforme  --<<<<<<<'
     
     
    f = open('fifi','w')
    f.write('ocean pacifique\t\t166241700 km2\n')
    f.write('ocean atlantique\t106000000 km2\n')
    f.write('ocean antarctique\t20327000 km2\n')
    f.write('ocean arctique\t\t14090000 km2\n')
    f.close()
     
    f = open('fifi','r')
    ch = f.read()
    f.close()
     
    print '-----------------------------------------'
    print '[ch] =\n',[ch],'\n'
    print 'avec pattern =',r'((^ocean.+ique.+\n)+\Z)','\n'
    m = re.match('((^ocean.+ique.+\n)+\Z)',ch,re.M)
    if m:
        print m.groups()
        print [m.group()]
        print '-- fichier OK --'
    else:
        print '>>>>>--  au moins une ligne non conforme  --<<<<<<<'
    -----------------------------------------
    [ch] =
    ['ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean indien\t\t75000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2\n']

    avec pattern = (((^ocean.+ique.+\n)+)\Z)

    >>>>>-- au moins une ligne non conforme --<<<<<<<
    -----------------------------------------
    [ch] =
    ['ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2\n']

    avec pattern = ((^ocean.+ique.+\n)+\Z)

    ('ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2\n', 'ocean arctique\t\t14090000 km2\n')
    ['ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2\n']
    -- fichier OK --
    Reste à pouvoir qualifier un fichier de OK même si sa dernière ligne ne comporte pas de '\n' à sa fin, donc à la fin du fichier. Il faut en fait déplacer le '\Z' à l'intérieur de chaque test de ligne en le mettant dans une alternative '\n|\Z'.

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    f = open('fifi','w')
    f.write('ocean pacifique\t\t166241700 km2\n')
    f.write('ocean atlantique\t106000000 km2\n')
    f.write('ocean antarctique\t20327000 km2\n')
    f.write('ocean arctique\t\t14090000 km2')
    f.close()
     
    f = open('fifi','r')
    ch = f.read()
    f.close()
     
    print '-----------------------------------------'
    print '[ch] =\n',[ch],'\n'
    print 'avec pattern =',r'((^ocean.+ique.+\n)+\Z)','\n'
    m = re.match('((^ocean.+ique.+\n)+\Z)',ch,re.M)
    if m:
        print m.groups()
        print [m.group()]
        print '-- fichier OK --'
    else:
        print '>>>>>--  au moins une ligne non conforme  --<<<<<<<'
     
     
     
     
     
    f = open('fifi','w')
    f.write('ocean pacifique\t\t166241700 km2\n')
    f.write('ocean atlantique\t106000000 km2\n')
    f.write('ocean antarctique\t20327000 km2\n')
    f.write('ocean arctique\t\t14090000 km2')
    f.close()
     
    f = open('fifi','r')
    ch = f.read()
    f.close()
     
    print '-----------------------------------------'
    print '[ch] =\n',[ch]
    print 'avec pattern =',r'((^ocean.+ique.+(\n|\Z))+)','\n'
    m = re.match('((^ocean.+ique.+(\n|\Z))+)',ch,re.M)
    if m:
        print m.groups()
        print [m.group()]
        print '-- fichier OK --'
    else:
        print '>>>>>--  au moins une ligne non conforme  --<<<<<<<'
    Et ça marche ! :
    -----------------------------------------
    [ch] =
    ['ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2']

    avec pattern = ((^ocean.+ique.+\n)+\Z)

    >>>>>-- au moins une ligne non conforme --<<<<<<<
    -----------------------------------------
    [ch] =
    ['ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2']
    avec pattern = ((^ocean.+ique.+(\n|\Z))+)

    ('ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2', 'ocean arctique\t\t14090000 km2', '')
    ['ocean pacifique\t\t166241700 km2\nocean atlantique\t106000000 km2\nocean antarctique\t20327000 km2\nocean arctique\t\t14090000 km2']
    -- fichier OK --

  7. #7
    Membre Expert
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Par défaut
    Bon, c'est pas tout ça... mais il reste ton problème à traiter.


    «4 caractères en majuscule puis deux slashs»
    cela fait:
    "[A-Z}{4}//"

    «puis une valeur décimale de 10 caractères maximum deux slash»
    cela fait:
    "\d(,\d{1,7})|(\d,\d{0,6})|(\d{2},\d{0,5})|(\d{3},\d{0,4})|(\d{4},\d{0,3})|(\d{5},\d{0,2})|(\d{6},\d{0,1})|(\d{7},)\d//"

    Si, si.
    Je n'ai pas trouvé plus court pour représenter un nombre décimal de 3 à 10 caractères, en partant de l'hypothèse qu'il a toujours au moins 2 chiffres de part et d'autre de la virgule.
    Et que cette virgule est unique.
    Parce qu'avec "[\d,]{10}" , on matche tout un tas de trucs comme "123,456789" , "123,,56704" ou ",,234,4,78". Et ça ne matche pas les nombres décimaux de moins de 10 caractères comme "12,474".

    On doit pouvoir améliorer cette horrible portion de regex.
    Pour simplifier je prends "[\d,]{3,10}" pour représenter le décimal.
    C'est à toi de préciser ce que signifie «nombre décimal à 10 caractères maximum».


    "[A-Z}{4}//[\d,]{3,10}//"
    Il n'y a pas besoin des parenthèse autour de [A-Z}{4} et de [\d,]{3,10} , sauf si tu veux en faire des groupes pour suivre leur participation à des matchings au moyen de la fonction groups().


    Ensuite, j'ai beau tourner la suite dans tous les sens, je n'arrive pas à comprendre ce signifie exactement «puis éventuellement 5 lignes supplémentaires de 0 a 35 caractères».
    Est-ce que chaque ligne supplémentaire fait 0 à 35 caractères ?
    Est-ce que 0 à 35 caractères peuvent s'étaler sur p[lusieurs lignes, 5 au maximum ?
    Est-ce qu'il y a obligatoirement un line break '\n' après "[A-Z}{4}//[\d,]{3,10}//" en cas de lignes supplémentaires, ou les caractères supplémentaires peuvent commencer juste après les deux derniers '//' ?

    Bon. Je prends la chaine "ceciestune:successionde35caracteres" et je suppose que tu veux détecter les cas suivants:

    "[A-Z]{4}//[\d,]{3,10}//"
    "[A-Z]{4}//[\d,]{3,10}//ceci"
    "[A-Z]{4}//[\d,]{3,10}//ceci\n"
    "[A-Z]{4}//[\d,]{3,10}//ceci\nest"
    "[A-Z]{4}//[\d,]{3,10}//ceci\nest\n"
    "[A-Z]{4}//[\d,]{3,10}//ceci\nest\nune:"
    "[A-Z]{4}//[\d,]{3,10}//ceci\nest\nune:\n"
    "[A-Z]{4}//[\d,]{3,10}//ceci\nest\nune:\nsucce"
    "[A-Z]{4}//[\d,]{3,10}//ceci\nest\nune:\nsucce\n"
    "[A-Z]{4}//[\d,]{3,10}//ceci\nest\nune:\nsucce\nssionde"
    "[A-Z]{4}//[\d,]{3,10}//ceci\nest\nune:\nsucce\nssionde\n"
    "[A-Z]{4}//[\d,]{3,10}//ceci\nest\nune:\nsucce\nssionde\n35caracteres"
    "[A-Z]{4}//[\d,]{3,10}//ceci\nest\nune:\nsucce\nssionde\n35caracteres\n"

    Je vais chercher à partir de ça. Mais ce n'est peut être pas du tout ce que tu recherches.
    Si tu passes par ici, précise un peu ce que tu veux faire STP.

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

Discussions similaires

  1. Besoin d'aide pour remplacer avec expression régulière sur plusieurs lignes
    Par MediaVistaIntel dans le forum Général Python
    Réponses: 11
    Dernier message: 01/12/2011, 14h19
  2. [PHP 5.2] expression reguliere sur multiline
    Par Papy214 dans le forum Langage
    Réponses: 6
    Dernier message: 16/04/2009, 10h29
  3. Expression régulière sur même ligne
    Par knebhi dans le forum Langage
    Réponses: 1
    Dernier message: 20/03/2009, 17h49
  4. expression régulière sur plusieurs lignes
    Par [Hugo] dans le forum Langage
    Réponses: 6
    Dernier message: 01/07/2008, 12h48
  5. expressions regulieres sur advice
    Par austin P. dans le forum Spring
    Réponses: 2
    Dernier message: 17/07/2007, 18h07

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