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 :

Expressions régulières et caractères accentués


Sujet :

Python

Vue hybride

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 19
    Par défaut Expressions régulières et caractères accentués
    Bonjour à tous,

    je viens de débuter avec les regexp sous python.

    je cherche à matcher des caractères accentués. D'après la doc rien de bien sorcier à condition de compiler ma regexp avec le flag re.LOCALE (si j'ai bien compris à quoi servait ce flag)

    Or je n'y suis pas arrivé sans définir explicitement mes caractères sous forme de code point unicode dans ma regex, ce qui finalement annule un peu l'intérêt des regexp...

    Voilà mes tests :

    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
    80
     
    Python 2.5.2 (r252:60911, Jan  4 2009, 17:40:26)
    [GCC 4.3.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import re
    >>> import locale
    >>> locale.getdefaultlocale()
    ('fr_FR', 'UTF8')
    >>> locale.setlocale(locale.LC_ALL,  None)
    'C'
    >>> locale.setlocale(locale.LC_ALL,  '')
    'fr_FR.UTF-8'
    >>> locale.setlocale(locale.LC_ALL,  None)
    'fr_FR.UTF-8'
    >>> pattern = ur'^\w+$'
    >>> pattern
    u'^\\w+$'
    >>> ro = re.compile(pattern, re.LOCALE)
    >>> ro
    <_sre.SRE_Pattern object at 0xb7df3520>
    >>> import sys
    >>> print sys.stdin.encoding
    UTF-8
    >>> # mo : match object
    >>> # premier essai avec une byte string
    >>> # 'frédéric' : 'fr\xc3\xa9d\xc3\xa9ric'
    >>> # je suppose que python encode cette chaîne utf-8
    >>> # en unicode pour le moteur de regex
    >>> # du coup la séquence de deux héxa \xc3\xa9 devrait être
    >>> # vue comme un seul caractère é
    >>> # compiler avec le flag re.LOCALE \w devrait matcher
    >>> # ce é
    >>> mo = ro.match('frédéric')
    >>> type(mo)
    <type 'NoneType'>
     
    >>> # test en enlevant les ancres de ma regexp
    >>> pattern = ur'\w+'
    >>> ro = re.compile(pattern, re.LOCALE)
    >>> mo = ro.match('frédéric')
    >>> type(mo)
    <type '_sre.SRE_Match'>
    >>> mo.string
    'fr\xc3\xa9d\xc3\xa9ric'
    >>> mo.group(0)
    'fr'
    >>> mo.groups()
    ()
    >>> mo.start(0)
    0
    >>> mo.end(0)
    2
    >>> mo.group(1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    IndexError: no such group
    >>> # le moteur de regexp n'a donc pas reconnu le é
    >>> # test : en admettant que python fournisse une chaîne type latin1 (donc la séquence utf-8 est vue comme
    >>> # deux caractères non acceptables dans un mot)
    >>> # il faut convertir la chaîne à tester en chaîne unicode
    >>> mo = ro.match(u'frédéric')
    >>> type(mo)
    <type '_sre.SRE_Match'>
    >>> mo.string
    u'fr\xe9d\xe9ric'
    >>> mo.group(0)
    u'fr'
    >>> # la seule solution que j'ai trouvé c'est d'insérer des code point unicode dans
    >>> # mon pattern
    >>> # voir http://www.regular-expressions.info/python.html
    >>> pattern = ur'^\w+\u00E9\w+\u00E9\w+$'
    >>> ro = re.compile(pattern)
    >>> mo = ro.match(u'frédéric')
    >>> type(mo)
    <type '_sre.SRE_Match'>
    >>> mo.string
    u'fr\xe9d\xe9ric'
    >>> mo.group(0)
    u'fr\xe9d\xe9ric'
    >>> # ça marche
    Est-ce que j'aurais loupé quelque chose ? (en tout cas j'espère)


    merci par avance,

    Frédéric

  2. #2
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    Or je n'y suis pas arrivé sans définir explicitement mes caractères sous forme de code point unicode dans ma regex
    Je connais que très peu les regexp, mais si tu es sous python 2.x pourquoi ne pas encoder les chaines à matcher en utf-8 avant de les matcher avec deux lignes du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ligne_a_matcher='éèà'
    try: ligne_a_matcher=ligne_a_matcher.encode('utf-8')
    except : None
    Comme personne ne t'a encore répondu, tu peux toujours essayer... j'éspère que ça fonctionnera

    Edit: pour python 3, la manip devrait être différente mais le fond reste le même

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 19
    Par défaut
    Salut,
    oui je vais essayer ça et poste le résultat

    nb. : j'aime bien ta signature, c'est un peu ce que je me dis tous les matins au boulot...

    Frédéric

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 19
    Par défaut
    Bon voilà ce que j'ai pu comprendre du fonctionnement des regex et unicode.

    note : les tests sont faits avec les locales suivantes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    >>> import locale
    >>> locale.getdefaultlocale()
    ('fr_FR', 'UTF8')
    >>> locale.setlocale(locale.LC_ALL, None)
    'C'
    >>> locale.setlocale(locale.LC_ALL, '')
    'fr_FR.UTF-8'
    >>> locale.setlocale(locale.LC_ALL, None)
    'fr_FR.UTF-8'
    et l'interpréteur à l'encodage suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    >>> import sys
    >>> print sys.stdin.encoding
    UTF-8
    1°) Visiblement il n'y a pas de conversion implicite par le moteur de regexp des patterns ou strings. ex. :

    a°) un pattern byte string matche une byte string, les deux devant être dans l'encodage donné par les locales (ici utf-8) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) 
    [GCC 4.3.3] on linux2                                 
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import re
    >>> pat = r'frédéric'
    >>> ro = re.compile(pat)
    >>> mo = ro.match('frédéric')
    >>> mo                               
    <_sre.SRE_Match object at 0x98959c0>                 
    >>> mo.group()                  
    'fr\xc3\xa9d\xc3\xa9ric'
    b°) un pattern unicode matche une string unicode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) 
    [GCC 4.3.3] on linux2                                 
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import re
    >>> pat = ur'frédéric'
    >>> ro = re.compile(pat)
    >>> mo = ro.match(u'frédéric')
    >>> mo                               
    <_sre.SRE_Match object at 0x98959c0>                 
    >>> mo.group()                  
    'fr\xe9d\xe9ric'
    c°) mais un pattern unicode ne matche pas une byte string et vice versa :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) 
    [GCC 4.3.3] on linux2                                 
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import re
    >>> pat = ur'frédéric'
    >>> ro = re.compile(pat)
    >>> mo = ro.match('frédéric')
    >>> type(mo)
    NoneType
    2°) d'après la doc, les options re.UNICODE et re.LOCALE modifie l'interprétation des caractères spéciaux dans le pattern : \w \W \d \D \s \S \B \b ...
    et selon moi l'encodage de la string représentant le pattern est indépendant de l'option choisie

    a°) bizarrement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) 
    [GCC 4.3.3] on linux2                                 
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import re
    >>> pat = r'\w+'
    >>> ro = re.compile(pat, re.LOCALE)
    >>> mo = ro.match('frédéric')
    >>> type(mo)
    NoneType
    b°) avec l'option re.UNICODE et une string unicode, par contre, les caractères spéciaux sont bien interprétés :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) 
    [GCC 4.3.3] on linux2                                 
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import re
    >>> pat = r'\w+'
    >>> ro = re.compile(pat, re.UNICODE)
    >>> mo = ro.match(u'frédéric')
    >>> mo.group()
    u'fr\xe9d\xe9ric'
    c°) logiquement : si ma chaîne est une byte string, python la comprend comme une suite de points de code unicode;

    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
     
    >>> pat = r'\w+'
    >>> ro = re.compile(pat, re.UNICODE)
    >>> mo = ro.match('frédéric')
    >>> mo
    <_sre.SRE_Match object at 0x9895aa0>
    >>> mo.group()
    'fr\xc3'
    >>> print u'\u00C3'
    Ã
    >>> print u'\u00A9'
    ©
    >>> pat_1 = ur'\w'
    >>> ro_1 = re.compile(pat_1, re.UNICODE)
    >>> mo_1 = ro_1.match(u'©')
    >>> mo_1
    >>> type(mo_1)
    <type 'NoneType'>
    >>> pat_1 = ur'\W'
    >>> ro_1 = re.compile(pat_1, re.UNICODE)
    >>> mo_1 = ro_1.match(u'©')
    >>> mo_1
    <_sre.SRE_Match object at 0x9895ad8>
    >>> mo_1.group()
    u'\xa9'
    ici, le 'é' est codé en '\xc3\xa9' puisque ma locale est utf-8, python considère donc \xc3 comme un point de code représentant le 'Ã' et matche, alors que le '©' (point de code \xa9) ne matche pas.

    Bon week-end,

    Frédéric

Discussions similaires

  1. Expression régulière avec caractères optionnels
    Par Muetdhiver dans le forum Langages de programmation
    Réponses: 2
    Dernier message: 05/02/2013, 12h02
  2. Réponses: 2
    Dernier message: 05/05/2011, 10h37
  3. [Expressions régulières] le caractère spécial "?"
    Par CedrX dans le forum Administration système
    Réponses: 4
    Dernier message: 08/01/2010, 13h38
  4. Expression régulière, supprimer caractères non numérique
    Par Scinza38 dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 22/11/2009, 11h19
  5. expression régulière et caractères spéciaux
    Par Jasmine80 dans le forum Langage
    Réponses: 6
    Dernier message: 13/03/2008, 12h23

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