Sam & Max » string http://sametmax.com Du code, du cul Sat, 07 Nov 2015 10:56:13 +0000 en-US hourly 1 http://wordpress.org/?v=4.1 Article retiré pour cause de grosse merde 4 http://sametmax.com/nested-format-expansion-thats-a-swag-title-cracker/ http://sametmax.com/nested-format-expansion-thats-a-swag-title-cracker/#comments Thu, 19 Dec 2013 08:10:32 +0000 http://sametmax.com/?p=8158 Désolé pour ceux qui ont reçu l’article via RSS ou email. Je le retire. C’était de la merde.

]]>
http://sametmax.com/nested-format-expansion-thats-a-swag-title-cracker/feed/ 4
Les expressions rationnelles en Python, parfois overkill 14 http://sametmax.com/les-expressions-rationnelles-en-python-parfois-overkill/ http://sametmax.com/les-expressions-rationnelles-en-python-parfois-overkill/#comments Wed, 07 Aug 2013 11:40:11 +0000 http://sametmax.com/?p=7042 J’adore les regex, et d’ailleurs il faudra que je fasse une série d’articles sur le sujet, un peu comme le guide de la POO.

Mais dans un langage comme Python, il y a de nombreuses solutions à mettre en oeuvre avant d’utiliser les regex.

Pour vérifier si une chaîne est dans une autre, utilisez in :

>>> 'a' in 'chat'
True
>>> 'a' in 'chien'
False
>>> 'a' in 'CHAT'.lower() # ignorer la casse
True

Pour savoir si un chaîne est au début ou à la fin, utilisez startswith() et endswith() :

>>> 'achat'.startswith('a')
True
>>> 'chat'.startswith('a')
False
>>> 'acheta'.endswith('a')
True

Pour savoir si la chaîne est d’un type particulier, utiliser les méthodes is* :

>>> '555'.isdigit()
True
>>> ''.isdigit()
False
>>> '⑦'.isdigit()
True
>>> '444'.isdecimal()
True
>>> '444.55'.isdecimal()
False
>> '⑦'.isdecimal()
False
>>> '879fds'.isalpha()
False
>>> 'fsdqfsqd'.isalpha()
True
>>> 'fsdqfsqd'.islower()
True
>>> 'fsdqFFsqd'.islower()
False
>>> '879fds'.isalnum()
True
>>> '879fds-'.isalnum()
False
>>> ' \t\n'.isspace()
True
>>> ' \t\n fdsfd'.isspace()
False

Si vous voulez manipuler la chaîne pour en extraire une partie, utilisez split() (ou rsplit(), lsplit() pour travailler sur la droite ou la gauche de la chaîne) :

>>> s = """Mais, vous savez, moi je ne crois pas qu'il y ait de bonne ou de mauvaise situation. Moi, si je devais résumer ma vie aujourd'hui avec vous, je dirais que c'est d'abord des rencontres, des gens qui m'ont tendu la main, peut-être à un moment où je ne pouvais pas, où j'étais seul chez moi. Et c'est assez curieux de se dire que les hasards, les rencontres forgent une destinée... Parce que quand on a le goût de la chose, quand on a le goût de la chose bien faite, le beau geste, parfois on ne trouve pas l'interlocuteur en face, je dirais, le miroir qui vous aide à avancer. Alors ce n'est pas mon cas, comme je le disais là, puisque moi au contraire, j'ai pu ; et je dis merci à la vie, je lui dis merci et je chante la vie, je danse la vie... Je ne suis qu'amour ! Et finalement, quand beaucoup de gens aujourd'hui me disent "Mais comment fais-tu pour avoir cette humanité ?", et bien je leur réponds très simplement, je leur dis que c'est ce goût de l'amour, ce goût donc qui m'a poussé aujourd'hui à entreprendre une construction mécanique, mais demain, qui sait, peut-être simplement à me mettre au service de la communauté, à faire le don... le don de soi."""
>>> s.split()
[u'Mais,', u'vous', u'savez,', u'moi', u'je', u'ne', u'crois', u'pas', u"qu'il", u'y', u'ait', u'de', u'bonne', u'ou', u'de', u'mauvaise', u'situation.', u'Moi,', u'si', u'je', u'devais', u'r\xe9sumer', u'ma', u'vie', u"aujourd'hui", u'avec', u'vous,', u'je', u'dirais', u'que', u"c'est", u"d'abord", u'des', u'rencontres,', u'des', u'gens', u'qui', u"m'ont", u'tendu', u'la', u'main,', u'peut-\xeatre', u'\xe0', u'un', u'moment', u'o\xf9', u'je', u'ne', u'pouvais', u'pas,', u'o\xf9', u"j'\xe9tais", u'seul', u'chez', u'moi.', u'Et', u"c'est", u'assez', u'curieux', u'de', u'se', u'dire', u'que', u'les', u'hasards,', u'les', u'rencontres', u'forgent', u'une', u'destin\xe9e...', u'Parce', u'que', u'quand', u'on', u'a', u'le', u'go\xfbt', u'de', u'la', u'chose,', u'quand', u'on', u'a', u'le', u'go\xfbt', u'de', u'la', u'chose', u'bien', u'faite,', u'le', u'beau', u'geste,', u'parfois', u'on', u'ne', u'trouve', u'pas', u"l'interlocuteur", u'en', u'face,', u'je', u'dirais,', u'le', u'miroir', u'qui', u'vous', u'aide', u'\xe0', u'avancer.', u'Alors', u'ce', u"n'est", u'pas', u'mon', u'cas,', u'comme', u'je', u'le', u'disais', u'l\xe0,', u'puisque', u'moi', u'au', u'contraire,', u"j'ai", u'pu', u';', u'et', u'je', u'dis', u'merci', u'\xe0', u'la', u'vie,', u'je', u'lui', u'dis', u'merci', u'et', u'je', u'chante', u'la', u'vie,', u'je', u'danse', u'la', u'vie...', u'Je', u'ne', u'suis', u"qu'amour", u'!', u'Et', u'finalement,', u'quand', u'beaucoup', u'de', u'gens', u"aujourd'hui", u'me', u'disent', u'"Mais', u'comment', u'fais-tu', u'pour', u'avoir', u'cette', u'humanit\xe9', u'?",', u'et', u'bien', u'je', u'leur', u'r\xe9ponds', u'tr\xe8s', u'simplement,', u'je', u'leur', u'dis', u'que', u"c'est", u'ce', u'go\xfbt', u'de', u"l'amour,", u'ce', u'go\xfbt', u'donc', u'qui', u"m'a", u'pouss\xe9', u"aujourd'hui", u'\xe0', u'entreprendre', u'une', u'construction', u'm\xe9canique,', u'mais', u'demain,', u'qui', u'sait,', u'peut-\xeatre', u'simplement', u'\xe0', u'me', u'mettre', u'au', u'service', u'de', u'la', u'communaut\xe9,', u'\xe0', u'faire', u'le', u'don...', u'le', u'don', u'de', u'soi.']
>>> s.split()[0]
u'Mais,'
>>> s.split()[5:7]
[u'ne', u'crois']
>>> s.split(',')
[u'Mais', u' vous savez', u" moi je ne crois pas qu'il y ait de bonne ou de mauvaise situation. Moi", u" si je devais r\xe9sumer ma vie aujourd'hui avec vous", u" je dirais que c'est d'abord des rencontres", u" des gens qui m'ont tendu la main", u' peut-\xeatre \xe0 un moment o\xf9 je ne pouvais pas', u" o\xf9 j'\xe9tais seul chez moi. Et c'est assez curieux de se dire que les hasards", u' les rencontres forgent une destin\xe9e... Parce que quand on a le go\xfbt de la chose', u' quand on a le go\xfbt de la chose bien faite', u' le beau geste', u" parfois on ne trouve pas l'interlocuteur en face", u' je dirais', u" le miroir qui vous aide \xe0 avancer. Alors ce n'est pas mon cas", u' comme je le disais l\xe0', u' puisque moi au contraire', u" j'ai pu ; et je dis merci \xe0 la vie", u' je lui dis merci et je chante la vie', u" je danse la vie... Je ne suis qu'amour ! Et finalement", u' quand beaucoup de gens aujourd\'hui me disent "Mais comment fais-tu pour avoir cette humanit\xe9 ?"', u' et bien je leur r\xe9ponds tr\xe8s simplement', u" je leur dis que c'est ce go\xfbt de l'amour", u" ce go\xfbt donc qui m'a pouss\xe9 aujourd'hui \xe0 entreprendre une construction m\xe9canique", u' mais demain', u' qui sait', u' peut-\xeatre simplement \xe0 me mettre au service de la communaut\xe9', u' \xe0 faire le don... le don de soi.']
>>> s.split('.')
[u"Mais, vous savez, moi je ne crois pas qu'il y ait de bonne ou de mauvaise situation", u" Moi, si je devais r\xe9sumer ma vie aujourd'hui avec vous, je dirais que c'est d'abord des rencontres, des gens qui m'ont tendu la main, peut-\xeatre \xe0 un moment o\xf9 je ne pouvais pas, o\xf9 j'\xe9tais seul chez moi", u" Et c'est assez curieux de se dire que les hasards, les rencontres forgent une destin\xe9e", u'', u'', u" Parce que quand on a le go\xfbt de la chose, quand on a le go\xfbt de la chose bien faite, le beau geste, parfois on ne trouve pas l'interlocuteur en face, je dirais, le miroir qui vous aide \xe0 avancer", u" Alors ce n'est pas mon cas, comme je le disais l\xe0, puisque moi au contraire, j'ai pu ; et je dis merci \xe0 la vie, je lui dis merci et je chante la vie, je danse la vie", u'', u'', u' Je ne suis qu\'amour ! Et finalement, quand beaucoup de gens aujourd\'hui me disent "Mais comment fais-tu pour avoir cette humanit\xe9 ?", et bien je leur r\xe9ponds tr\xe8s simplement, je leur dis que c\'est ce go\xfbt de l\'amour, ce go\xfbt donc qui m\'a pouss\xe9 aujourd\'hui \xe0 entreprendre une construction m\xe9canique, mais demain, qui sait, peut-\xeatre simplement \xe0 me mettre au service de la communaut\xe9, \xe0 faire le don', u'', u'', u' le don de soi', u'']

Et n’oubliez pas que vous pouvez appeler join() derrière.

Si vous devez altérer la chaîne, utilisez strip() (et rstrip(), lstrip()) ou replace() :

>>> "Les nouilles cuisent au jus de canne".replace('noui', 'coui').replace('cui', 'nui').replace('jus', 'cul').replace('canne', 'jeanne')
u'Les couilles nuisent au cul de jeanne'
>>> "                               .                       ".strip()
u'.'
>>> "===                               .                       ======".strip("= ")
u'.'

En plus, les chaînes sont itérables, indexables et sliceables, donc :

>>> s = """And I will strike down upon thee with great vengeance and furious anger those who attempt to poison and destroy my brothers. And you will know my name is the Lord when I lay my vengeance upon you!"""
>>> s[3:30:3]
u' wltkdnp '
>>> s.split()
[u'And', u'I', u'will', u'strike', u'down', u'upon', u'thee', u'with', u'great', u'vengeance', u'and', u'furious', u'anger', u'those', u'who', u'attempt', u'to', u'poison', u'and', u'destroy', u'my', u'brothers.', u'And', u'you', u'will', u'know', u'my', u'name', u'is', u'the', u'Lord', u'when', u'I', u'lay', u'my', u'vengeance', u'upon', u'you!']
>>> s[0]
u'A'
>>> ''.join([(l.upper() if i % 2 else l) for i, l in enumerate(s)])
u'ANd I wIlL StRiKe dOwN UpOn tHeE WiTh gReAt vEnGeAnCe aNd fUrIoUs aNgEr tHoSe wHo aTtEmPt tO PoIsOn aNd dEsTrOy mY BrOtHeRs. AnD YoU WiLl kNoW My nAmE Is tHe LOrD WhEn I lAy mY VeNgEaNcE UpOn yOu!'

Bref, avant de sortir le bazooka, souvenez-vous que vous avez un arsenal déjà très approprié pour traiter les strings, dont les perfs seront en plus probablement meilleures.

]]>
http://sametmax.com/les-expressions-rationnelles-en-python-parfois-overkill/feed/ 14
% ou format() en Python ? 24 http://sametmax.com/ou-format-en-python/ http://sametmax.com/ou-format-en-python/#comments Fri, 21 Jun 2013 10:47:41 +0000 http://sametmax.com/?p=6416 Cet article a été mis à jour et contient maintenant du code Python en version 3

On a reçu un mail du genre :

Salut les mecs!

Je me demandais si il valait mieux utiliser format() ou % quand on veut insérer une variable dans une chaîne?
Je comprend pas vraiment quelle est la différence entre les deux…l’un est-il plus rapide? Plus fiable?

Merci les mecs!

Je suppose que d’autres personnes se posent la même question, du coup je poste ça là une bonne fois pour toutes.

En résumé : avec le recul, il n’y en a pas de meilleur. C’est une question de facilité d’usage et de lisibilité.

En effet, % était parti pour être déprécié en Python 3, mais ce n’est jamais arrivé, pour plusieurs raisons :

  • % est souvent plus court à taper.
  • le module logging utilise toujours ce format.
  • avec Python 3.5, le type bytes va de nouveau utiliser cet opérateur pour le formatage.

Si votre formatage est simple ou si vous utilisez des bytes ou le module logging, utilisez %:

>>> "je suis hyper %s. Brouuuuahhh" % "content"
    'je suis hyper content. Brouuuuahhh'

L’équivalent avec format() serait :

>>>  "je suis hyper {}. Brouuuuahhh".format("content")
    'je suis hyper content. Brouuuuahhh'

On y gagne pas, c’est plus long à taper car il y a plus de lettres mais aussi parce que qu’il y a beaucoup plus de caractères spéciaux à atteindre sur son clavier : {}.() contre %.

On table ici sur la facilité et la rapidité d’usage.

Si votre formatage a beaucoup de variables, que vos variables sont déjà dans un dictionnaire, que votre texte est long ou que vous avez besoin de formats avancés, utilisez format():

"{value}{unit} ({time:%H:%M:%S})".format(value=3, unit="ppm", time=datetime.now())
'3ppm (10:53:04)'

L’équivalent avec % serait:

date = datetime.now().strftime("%H:%M:%S")
"%(value)s%(unit)s (%(time)s)" % {"value": 3, "unit": "ppm", "time": date}

Moins lisible, plus verbeux. format() gagne toujours dès qu’on a un message complexe. Mais ça n’arrive pas aussi souvent qu’on ne le pense, du coup % a encore de beaux jours devant lui.

Avec Python 3.6 arrivera une nouvelle manière de faire, les f-strings. Si vous avez la chance d’utiliser la 3.6, les f-strings peuvent remplacer avantageusement la plupart des formes ci-dessus :

>>> value = 3
>>> unit = "ppm"
>>> f'{value}{unit} ({datetime.now():%H:%M:%S})'
'3ppm (10:53:54)'

Mais il faudra attendre 2016…

]]>
http://sametmax.com/ou-format-en-python/feed/ 24
Le piège de la méthode strip() des chaînes en Python 6 http://sametmax.com/le-piege-de-la-methode-strip-des-chaines-en-python/ http://sametmax.com/le-piege-de-la-methode-strip-des-chaines-en-python/#comments Mon, 01 Oct 2012 13:27:45 +0000 http://sametmax.com/?p=2309 strip(), et ses acolytes lstrip() et rstrip(), ne retirent pas la chaîne de caractères aux extrémités d'une autre chaîne de caractères.]]> strip(), et ses acolytes lstrip() et rstrip(), ne retirent pas la chaîne de caractères aux extrémités d’une autre chaîne de caractères.

Elles retirent des extrémités toutes lettres qui sont dans la chaînes passée en paramètre. La nuance est subtile, mais c’est la différence entre ça:

>>> "# ##  # test ".strip('# ') # comportement attendu mais faux
'##  # test '

Et ça:

>>> "# ##  # test ".strip('# ') # comportement réel
'test'
]]>
http://sametmax.com/le-piege-de-la-methode-strip-des-chaines-en-python/feed/ 6
Comment marchent les “raw strings” en Python ? 7 http://sametmax.com/comment-marchent-les-raw-strings-en-python/ http://sametmax.com/comment-marchent-les-raw-strings-en-python/#comments Tue, 06 Mar 2012 16:13:04 +0000 http://sametmax.com/?p=241 Cet article a été mis à jour et contient maintenant du code Python en version 3

Dans certains tutos, notamment ceux sur les expressions rationnelles, on recommande d’utiliser les “raw strings”, en mettant un “r” devant la déclaration de la chaîne de caractères.

Par exemple :

'1?\d\d?'

Devient :

r'1?\d\d?'

À quoi cela sert-il ?

Voyons d’abord à quoi cela ne sert pas

  • Créer un type de string particulier. Il n’y a rien de tel qu’un type “raw string” en Python. La chaîne résultante est une chaîne ordinaire
  • Créer une chaîne destinée aux regexes. On utilise particulièrement la notation ‘r’ avec les regexs, mais ce n’est pas un type dédié

‘r’ est juste un modificateur, une sorte de paramètre. En effet, quand vous écrivez 'Salut !\n', vous n’écrivez PAS la chaîne “Salut ![LB]”. Vous dites à Python de créer un objet chaîne, de la même manière que vous lui demanderiez une instanciation en faisant MaClasse().

'Salut !\n' est juste une notation demandant de créer une chaîne, pas la chaîne elle-même. Cette notation dit à Python : À partir de cet instant dans le programme, tu vas créer un objet chaîne en mémoire, et voici les paramètres que je te donne pour le créer. La notation étant différente, on a l’illusion d’écrire la chaîne soi-même, mais en fait ce n’est pas différent d’un appel de fonction.

Quand vous faites 'Salut !\n', vous dites plus précisément à Python : Instancie un objet de type string, met les caractères S, a, l, u, t, espace et point d’exclamation dedans, suivi d’un saut de ligne. Cette notation, pour se faciliter la vie, permet de décrire “saut de ligne” en écrivant '\n'. Python analyse donc votre chaîne, cherche toutes les combinaisons de caractères spéciaux comme '\n', '\t', etc, et quand il crée l’objet en mémoire, il ajoute un saut de ligne ou une tabulation, et pas les caractères ‘\’ puis ‘n’ ou ‘t’.

Que se passe-t-il si vous voulez réellement ajouter ‘\’ et ‘n’ ?

Il faut utiliser une autre notation, l’échappement. On utilise un ‘\’ pour dire à Python: créer cet objet en mémoire, mais à cet endroit, ne tient pas compte de la combinaison de caractères spéciaux.

Ceci affiche un saut de ligne : print('\n est le caractère de saut de ligne')

Ceci affiche ‘\’, ‘n’ puis la phrase : print('\\n est le caractère de saut de ligne')

Mais il existe des cas où c’est très fastidieux et illisible. Notamment les expressions rationnelles, où les ‘\’ font partie intégrante du système.

Un exemple simple, vous voulez “C:\Program Files” dans une phrase :

Votre regex devra contenir ‘\P’. Sauf qu’en regex, ‘\P’ est un symbole spécial, donc il faut l’échapper, vous aurez donc ‘\\P’. Sauf qu’en Python, il faut échapper les ‘\’ pour qu’ils ne soient pas considérés comme caractères spéciaux, vous aurez donc ‘\\\\P’. Sur une regex complexe, ça devient vite très moche, et très dur à déboguer.

C’est là qu’intervient le modificateur ‘r’, qui précise à Python : quand tu vas créer cette chaîne en mémoire, met ces caractères dedans littéralement et considère qu’il n’y a aucune combinaison de caractères spéciaux.

En clair r'\n' sera ‘\’ puis ‘n’. Python ne va tout simplement par parser la chaîne, il va l’utiliser littéralement, d’où le “raw” string.

Il n’y a donc rien de spécial dans une chaîne créée avec le modificateur ‘r’, c’est une chaîne normale, qui est instanciée sans réfléchir par Python, sans chercher à être malin et comprendre des notations spéciales.

Ça ne veut pas dire qu’on ne peut pas avoir des sauts de ligne dans une chaîne créée avec ‘r’ :

>>> print(r"""1 + 1 = 
... 42""")
1 + 1
42

Ça veut juste dire que les notations spéciales ne seront pas analysées :

>>> print('1 + 1 =\n 42')
1 + 1 =
42
>>> print(r'1 + 1 =\n 42')
1 + 1 =\n 42

Il est facile de s’embrouiller les pinceaux à cause du shell Python :

>>> 'test\n'
'test\n'
>>> r'test\n'
'test\\n'
>>> print('test\n')
test
 
>>> print(r'test\n')
test\n

Il faut savoir que quand on affiche un objet sans utiliser print() dans le shell, ce dernier essaye de vous afficher une représentation de l’objet de telle sorte qu’il puisse être copié et collé par un dev, et recréer le même objet. En revanche, print() va afficher du texte formaté pour être lisible par un utilisateur final.

Enfin, les combinaisons de préfixes peuvent ou non être compatibles:

>>> ur'test\n' 
  File "<ipython-input-6-334281889b3a>", line 1
    ur'test\n'
           ^
SyntaxError: invalid syntax
>>> rb'test\n'
    b'test\\n'

Donc si vous faites un code compatible Python 2 et 3 en même temps, faites gaffe.

Si les fstrings sont acceptées, ‘f’ sera compatible avec ‘r’.

]]>
http://sametmax.com/comment-marchent-les-raw-strings-en-python/feed/ 7