Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Problème d'expression régulière (débutant)

13 réponses
Avatar
Pierre Bertet
Bonjour,

j'ai un petit problème avec une expression régulière, le texte à parser
est de la forme :


["cle_nom_fixe1"] = {
["cle_nom_imprevisible1"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible2"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible3"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}


...


["cle_nom_fixe2"] = {
}
}


Vous l'aurez compris, les valeurs qui m'intéressent sont à l'intérieur
des "cle_nom_imprevisible".


Je commence donc par récupérer la partie qui m'intéresse, de cette façon :

expr1 = re.compile('\["cle_nom_fixe1"\] = {(.*)\["cle_nom_fixe2"\]',re.S)
texte1 = expr1.search(contenu)
texte1 = texte1.group()

puis j'essaie d'isoler chaque "cle_nom_imprevisible", et c'est là que ça
coince :

expr2 = re.compile('\(["cle_nom_fixe3"\].*)\["cle_nom_fixe7"\].*',re.S)
texte2 = expr2.findall(texte1)

(la valeur de "cle_nom_fixe7" ne m'intéresse pas, heureusement!)

Puis :

for i in range(len(texte2)):
print texte2[i]+"\n____________________________\n"

Mais au lieu de s'arrêter à chaque ["cle_nom_fixe7"], il s'arrête à la
dernière, j'ai donc une seule entrée dans texte2 qui est :

["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible2"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible3"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"

Ce qui peut me sembler logique, puisque j'utilise .*

Mais alors comment faire?

Merci d'avance pour votre aide.

10 réponses

1 2
Avatar
bruno at modulix
Pierre Bertet wrote:
Bonjour,

(snip)


Je commence donc par récupérer la partie qui m'intéresse, de cette façon :

expr1 = re.compile('["cle_nom_fixe1"] = {(.*)["cle_nom_fixe2"]',re.S)


Premier conseil : utilise des raw strings pour tes expressions
régulières, ça t'évitera de te mélanger les pinceaux dans les échappements.
re.compile(r'["cle_nom_fixe1"] = {(.*)["cle_nom_fixe2"]', re.S)

puis j'essaie d'isoler chaque "cle_nom_imprevisible", et c'est là que ça
coince :

expr2 = re.compile('(["cle_nom_fixe3"].*)["cle_nom_fixe7"].*',re.S)
re.compile(r'(["cle_nom_fixe3"].*)["cle_nom_fixe7"]', re.S)


NB : tu a retapé ton code, ou c'est un vrai copié-collé ?

(la valeur de "cle_nom_fixe7" ne m'intéresse pas, heureusement!)

Puis :

for i in range(len(texte2)):
print texte2[i]+"n____________________________n"

Mais au lieu de s'arrêter à chaque ["cle_nom_fixe7"], il s'arrête à la
dernière,
(snip)

Ce qui peut me sembler logique, puisque j'utilise .*

Mais alors comment faire?


Utiliser le modifieur ? pour rentre l'expression 'non-greedy':
r'(["cle_nom_fixe3"].*?)["cle_nom_fixe7"]'

NB : non testé.

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"

Avatar
Pierre Bertet
Pierre Bertet wrote:

Je commence donc par récupérer la partie qui m'intéresse, de cette façon :

expr1 = re.compile('["cle_nom_fixe1"] = {(.*)["cle_nom_fixe2"]',re.S)


Premier conseil : utilise des raw strings pour tes expressions
régulières, ça t'évitera de te mélanger les pinceaux dans les échappements.
re.compile(r'["cle_nom_fixe1"] = {(.*)["cle_nom_fixe2"]', re.S)

Merci pour ce conseil.


Les raw strings permettent de ne pas interpréter les caractères
d'échappement c'est bien ça?
Mais alors pourquoi les appliquer ici, puisque j'ai besoin d'échapper le
caractère "["?

puis j'essaie d'isoler chaque "cle_nom_imprevisible", et c'est là que ça
coince :

expr2 = re.compile('(["cle_nom_fixe3"].*)["cle_nom_fixe7"].*',re.S)
re.compile(r'(["cle_nom_fixe3"].*)["cle_nom_fixe7"]', re.S)


NB : tu a retapé ton code, ou c'est un vrai copié-collé ?

Copié/collé, j'ai simplement changé les noms pour les rendre plus

explicites.

Utiliser le modifieur ? pour rentre l'expression 'non-greedy':
r'(["cle_nom_fixe3"].*?)["cle_nom_fixe7"]'

NB : non testé.

Ca fonctionne parfaitement, merci vraiment.


Mais pour être franc, j'ai du mal à comprendre pourquoi.
Le modifieur ? signifie "Ce qui précède apparaît 0 ou une fois", alors
qu'avant, il pouvait apparaître autant de fois que voulu.

Ca signifie donc que ["cle_nom_fixe7"] ne compte pas comme n'importe
quel caractère, à condition de mettre un modifieur?


Merci encore!


Avatar
bruno at modulix
Pierre Bertet wrote:

Pierre Bertet wrote:

Je commence donc par récupérer la partie qui m'intéresse, de cette
façon :

expr1 = re.compile('["cle_nom_fixe1"] >>> {(.*)["cle_nom_fixe2"]',re.S)



Premier conseil : utilise des raw strings pour tes expressions
régulières, ça t'évitera de te mélanger les pinceaux dans les
échappements.
re.compile(r'["cle_nom_fixe1"] = {(.*)["cle_nom_fixe2"]', re.S)

Merci pour ce conseil.


Les raw strings permettent de ne pas interpréter les caractères
d'échappement c'est bien ça?


Presque.

Mais alors pourquoi les appliquer ici, puisque j'ai besoin d'échapper le
caractère "["?


http://www.python.org/doc/2.4.2/lib/module-re.html
"""
Regular expressions use the backslash character ("") to indicate
special forms or to allow special characters to be used without invoking
their special meaning. This collides with Python's usage of the same
character for the same purpose in string literals; for example, to match
a literal backslash, one might have to write '\' as the pattern
string, because the regular expression must be "", and each backslash
must be expressed as "" inside a regular Python string literal.
"""

puis j'essaie d'isoler chaque "cle_nom_imprevisible", et c'est là que ça
coince :

expr2 = re.compile('(["cle_nom_fixe3"].*)["cle_nom_fixe7"].*',re.S)


re.compile(r'(["cle_nom_fixe3"].*)["cle_nom_fixe7"]', re.S)

NB : tu a retapé ton code, ou c'est un vrai copié-collé ?

Copié/collé, j'ai simplement changé les noms pour les rendre plus

explicites.


Alors ton expression avait un petit problème...

Utiliser le modifieur ? pour rentre l'expression 'non-greedy':
r'(["cle_nom_fixe3"].*?)["cle_nom_fixe7"]'

NB : non testé.

Ca fonctionne parfaitement,



Bon, tant mieux.

Mais pour être franc, j'ai du mal à comprendre pourquoi.
Le modifieur ? signifie "Ce qui précède apparaît 0 ou une fois", alors
qu'avant, il pouvait apparaître autant de fois que voulu.


http://www.python.org/doc/2.4.2/lib/re-syntax.html
"""
*?, +?, ??
The "*", "+", and "?" qualifiers are all greedy; they match as much
text as possible. Sometimes this behaviour isn't desired; if the RE <.*>
is matched against '<H1>title</H1>', it will match the entire string,
and not just '<H1>'. Adding "?" after the qualifier makes it perform the
match in non-greedy or minimal fashion; as few characters as possible
will be matched. Using .*? in the previous expression will match only
'<H1>'.
"""

Ca signifie donc que ["cle_nom_fixe7"] ne compte pas comme n'importe
quel caractère, à condition de mettre un modifieur?


Non. Ca signifie que "A.*B" va essayer de matcher le plus de caractères
possibles - jusqu'au dernier B exclus en l'occurrence-, alors que
"A.*?B" va s'arrêter au caractère précédent le premier B


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"



Avatar
Pierre Bertet
Pierre Bertet wrote:

Pierre Bertet wrote:

Je commence donc par récupérer la partie qui m'intéresse, de cette
façon :

expr1 = re.compile('["cle_nom_fixe1"] >>>> {(.*)["cle_nom_fixe2"]',re.S)


Premier conseil : utilise des raw strings pour tes expressions
régulières, ça t'évitera de te mélanger les pinceaux dans les
échappements.
re.compile(r'["cle_nom_fixe1"] = {(.*)["cle_nom_fixe2"]', re.S)

Merci pour ce conseil.


Les raw strings permettent de ne pas interpréter les caractères
d'échappement c'est bien ça?


Presque.

Mais alors pourquoi les appliquer ici, puisque j'ai besoin d'échapper le
caractère "["?


http://www.python.org/doc/2.4.2/lib/module-re.html
"""
Regular expressions use the backslash character ("") to indicate
special forms or to allow special characters to be used without invoking
their special meaning. This collides with Python's usage of the same
character for the same purpose in string literals; for example, to match
a literal backslash, one might have to write '\' as the pattern
string, because the regular expression must be "", and each backslash
must be expressed as "" inside a regular Python string literal.
"""

puis j'essaie d'isoler chaque "cle_nom_imprevisible", et c'est là que ça
coince :

expr2 = re.compile('(["cle_nom_fixe3"].*)["cle_nom_fixe7"].*',re.S)
re.compile(r'(["cle_nom_fixe3"].*)["cle_nom_fixe7"]', re.S)


NB : tu a retapé ton code, ou c'est un vrai copié-collé ?

Copié/collé, j'ai simplement changé les noms pour les rendre plus

explicites.


Alors ton expression avait un petit problème...

Utiliser le modifieur ? pour rentre l'expression 'non-greedy':
r'(["cle_nom_fixe3"].*?)["cle_nom_fixe7"]'

NB : non testé.

Ca fonctionne parfaitement,



Bon, tant mieux.

Mais pour être franc, j'ai du mal à comprendre pourquoi.
Le modifieur ? signifie "Ce qui précède apparaît 0 ou une fois", alors
qu'avant, il pouvait apparaître autant de fois que voulu.


http://www.python.org/doc/2.4.2/lib/re-syntax.html
"""
*?, +?, ??
The "*", "+", and "?" qualifiers are all greedy; they match as much
text as possible. Sometimes this behaviour isn't desired; if the RE <.*>
is matched against '<H1>title</H1>', it will match the entire string,
and not just '<H1>'. Adding "?" after the qualifier makes it perform the
match in non-greedy or minimal fashion; as few characters as possible
will be matched. Using .*? in the previous expression will match only
'<H1>'.
"""

Ca signifie donc que ["cle_nom_fixe7"] ne compte pas comme n'importe
quel caractère, à condition de mettre un modifieur?


Non. Ca signifie que "A.*B" va essayer de matcher le plus de caractères
possibles - jusqu'au dernier B exclus en l'occurrence-, alors que
"A.*?B" va s'arrêter au caractère précédent le premier B




Merci pour ces précieuses informations, je vais étudier tout ça.

--
Pierre Bertet.




Avatar
bruno at modulix
Pierre Bertet wrote:
(snip)

Merci pour ces précieuses informations,


De rien.

<ot>
ne le prends pas mal, mais si tu pouvais songer à épurer quelque peu le
message auquel tu réponds, la molette de ma souris t'en serais
reconnaissante !-)
</ot>

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"

Avatar
Gerard Flanagan
Pierre Bertet wrote:

Bonjour,

j'ai un petit problème avec une expression régulière, le texte à parser
est de la forme :


["cle_nom_fixe1"] = {
["cle_nom_imprevisible1"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible2"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible3"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}


...


["cle_nom_fixe2"] = {
}
}


Vous l'aurez compris, les valeurs qui m'intéressent sont à l'intéri eur
des "cle_nom_imprevisible".


Je commence donc par récupérer la partie qui m'intéresse, de cette façon :

expr1 = re.compile('["cle_nom_fixe1"] = {(.*)["cle_nom_fixe2"]',r e.S)
texte1 = expr1.search(contenu)
texte1 = texte1.group()

puis j'essaie d'isoler chaque "cle_nom_imprevisible", et c'est là que ça
coince :

expr2 = re.compile('(["cle_nom_fixe3"].*)["cle_nom_fixe7"].*',re.S)
texte2 = expr2.findall(texte1)

(la valeur de "cle_nom_fixe7" ne m'intéresse pas, heureusement!)


Mais alors comment faire?


Un autre facon d'aborder le probleme:

data1='''
["cle_nom_fixe1"] = {
["cle_nom_imprevisible1"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible2"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible3"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
}
'''

data2='''
["cle_nom_fixe1"] = {
["cle_nom_imprevisible1"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible2"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible3"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
}
["cle_nom_fixe2"] =
{
["cle_nom_imprevisible1"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible2"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
["cle_nom_imprevisible3"] = {
["cle_nom_fixe3"] = "valeur"
["cle_nom_fixe4"] = 123456
["cle_nom_fixe5"] = "valeur"
["cle_nom_fixe6"] = "valeur"
["cle_nom_fixe7"] = "valeur"
}
}
'''

def dict_from_string( data ):
d = ''.join(data.split())
d = '{' + d + '}'
d = d.replace('=',':')
d = d.replace('[',',')
d = d.replace(']','')
d = d.replace('{,','{')
return eval(d) # 'eval' - fais attention!

d1 = dict_from_string(data1)
d2 = dict_from_string(data2)

assert isinstance(d1,dict)
assert isinstance(d2,dict)
print d1
print d2

(on presuppose ni les cles ni les valeurs contient '=', '[', ']', '{'
ou '}' )

Gerard

Avatar
Pierre Bertet
<ot>
ne le prends pas mal, mais si tu pouvais songer à épurer quelque peu le
message auquel tu réponds, la molette de ma souris t'en serais
reconnaissante !-)
</ot>



Ca aussi, je prends, merci :)

Avatar
Bertrand B
Pierre Bertet wrote:
(snip)
Merci pour ces précieuses informations,


De rien.

<ot>
ne le prends pas mal, mais si tu pouvais songer à épurer quelque pe u le
message auquel tu réponds, la molette de ma souris t'en serais
reconnaissante !-)
</ot>

Et bien même si thunderbird n'est pas idéal comme lecteur de news

l'extension "quote collapse" pourrait économiser ta souris.

--
S'il y avait moins de monde dans la foule, il y aurait plus de place
pour chacun.
-+- Pierre Dac -+-


Avatar
bruno at modulix
Gerard Flanagan wrote:
(snip)
def dict_from_string( data ):
d = ''.join(data.split())
d = '{' + d + '}'
d = d.replace('=',':')
d = d.replace('[',',')
d = d.replace(']','')
d = d.replace('{,','{')
return eval(d) # 'eval' - fais attention!




A part pour un script jetable, c'est une solution plutôt plus à mon goût
... faudrait tester les perfs respectives.

Après, il y a aussi la solution d'écrire un vrai parseur, mais bon, ça
devient peut-être un poil overkill !-)

(on presuppose ni les cles ni les valeurs contient '=', '[', ']', '{'
ou '}' )


Ce qui peut se tester avec.... des expressions régulières !-)


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"

Avatar
Gerard Flanagan
bruno at modulix wrote:

Gerard Flanagan wrote:
(snip)

(on presuppose ni les cles ni les valeurs contient '=', '[', ']', '{'
ou '}' )


Ce qui peut se tester avec.... des expressions régulières !-)




:-)

comme on dit en anglais: "You can run, but you can't hide"!

(hesitant: "on peut s'enfuir, mais on ne peut pas se cacher"?)

Gerard


1 2