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

fonction de comparaison

8 réponses
Avatar
NicolasP
Bonjour,

Je cherche à faire une fonction de comparaison de chaine de caractères pour un tri "alpha-numérique".
Les chaines sont composées d'une partie alphabétique(facultative) et d'une partie numérique.
Soit :
"1" < "10"
"9" < "10"
"A1" < "A10"
"A9" < "A10"
"AA1" < "AA10"
"AA9" < "AA10"

"1" < "A1"
"A1" < "AA1"
"B1" < "AA1"
...

Clairement, il faut séparer la partie alphabétique et la partie numérique et traiter la partie numérique comme un nombre et non pas comme une chaine.

Comment faire cela simplement ?

Nicolas

8 réponses

Avatar
NicolasP
Le 22/10/2010 14:46, NicolasP a écrit :
Bonjour,

Je cherche à faire une fonction de comparaison de chaine de caractères pour un tri "alpha-numérique".
Les chaines sont composées d'une partie alphabétique(facultative) et d'une partie numérique.
Soit :
"1" < "10"
"9" < "10"
"A1" < "A10"
"A9" < "A10"
"AA1" < "AA10"
"AA9" < "AA10"

"1" < "A1"
"A1" < "AA1"
"B1" < "AA1"
....

Clairement, il faut séparer la partie alphabétique et la partie numérique et traiter la partie numérique comme un nombre et non pas comme une chaine.

Comment faire cela simplement ?

Nicolas



Rectification :
La partie alphabétique est soit présente soit absente dans les deux éléments à comparer
Donc "1" < "A1" n'a pas de sens.
Avatar
Alain Ketterlin
NicolasP writes:

Je cherche à faire une fonction de comparaison de chaine de caract ères
pour un tri "alpha-numérique". Les chaines sont composées d'une partie
alphabétique(facultative) et d'une partie numérique.



def couple(s):
t = s.rstrip("0123456789")
n = s[len(t):]
return (t,int(n))

ensuite tu peux faire couple(s1) < couple(s2)

-- Alain.
Avatar
Pierre Maurette
NicolasP, le 10/22/2010 a écrit :
Bonjour,

Je cherche à faire une fonction de comparaison de chaine de caractères pour
un tri "alpha-numérique".
Les chaines sont composées d'une partie alphabétique(facultative) et d'une
partie numérique.
Soit :
"1" < "10"
"9" < "10"
"A1" < "A10"
"A9" < "A10"
"AA1" < "AA10"
"AA9" < "AA10"

"1" < "A1"
"A1" < "AA1"
"B1" < "AA1"
...

Clairement, il faut séparer la partie alphabétique et la partie numérique et
traiter la partie numérique comme un nombre et non pas comme une chaine.

Comment faire cela simplement ?



Peut-être:
re.match('(D*)(.*)', chaine).groups()

ou plutôt:
pat = re.compile('(D*)(.*)')
#...
pat.match(chaine).groups()

un test:
for item in ('PIERRE', '128', 'PIERRE128', ''):
print pat.match(item).groups()

--
Pierre Maurette
Avatar
Pierre Quentel
On 22 oct, 14:46, NicolasP wrote:
Bonjour,

Je cherche à faire une fonction de comparaison de chaine de caractère s pour un tri "alpha-numérique".
Les chaines sont composées d'une partie alphabétique(facultative) et d'une partie numérique.
Soit :
"1" < "10"
"9" < "10"
"A1" < "A10"
"A9" < "A10"
"AA1" < "AA10"
"AA9" < "AA10"

"1" < "A1"
"A1" < "AA1"
"B1" < "AA1"
...

Clairement, il faut séparer la partie alphabétique et la partie num érique et traiter la partie numérique comme un nombre et non pas comme une chaine.

Comment faire cela simplement ?

Nicolas



Bonsoir Nicolas,

On peut le faire avec une classe :

=============
import string

class alphanum:

def __init__(self,data):
self.alpha = data.rstrip(string.digits)
self.num = int(data[len(self.alpha):])

def __cmp__(self,autre):
return cmp((self.alpha,self.num),(autre.alpha,autre.num))

assert alphanum("1")<alphanum("10")
assert alphanum("9")<alphanum("10")
assert alphanum("A1")<alphanum("A10")
assert alphanum("A9")<alphanum("A10")
assert alphanum("AA1")<alphanum("AA10")
assert alphanum("AA9")<alphanum("AA10")
assert alphanum("1")<alphanum("A1")
assert alphanum("A1")<alphanum("AA1")
assert alphanum("B1")<alphanum("AA1")
=================

mais le dernier test échoue : pouquoi B1 serait-il inférieur à AA1 ?
dans l'ordre alphabétique normal, B est après AA

A+
Pierre
Avatar
Daniel Gallavardin
Le 22/10/2010 14:46, NicolasP a écrit :
Bonjour,

Je cherche à faire une fonction de comparaison de chaine de caractères
pour un tri "alpha-numérique".
Les chaines sont composées d'une partie alphabétique(facultative) et
d'une partie numérique.
Soit :
"1" < "10"
"9" < "10"
"A1" < "A10"
"A9" < "A10"
"AA1" < "AA10"
"AA9" < "AA10"

"1" < "A1"
"A1" < "AA1"
"B1" < "AA1"
...

Clairement, il faut séparer la partie alphabétique et la partie
numérique et traiter la partie numérique comme un nombre et non pas
comme une chaine.

Comment faire cela simplement ?

Nicolas



Bonjour,
C'est généralisable assez facilement en décomposant la chaine en
tronçons numériques ou non, puis en convertissant les tronçons de
chiffres en nombre entiers:

def order(data, rc=re.compile('[0-9]+|[^0-9]+')):
'''Critere de tri'''
tmp = []
for item in rc.findall(data):
try:
item = int(item)
except ValueError:
pass
tmp.append(item)
return tuple(tmp)

order('A10') # Cas simple






('A', 10)
order('Page15_ligne234_caractere82+$~33d2!!!') # ou complexe






('Page', 15, '_ligne', 234, '_caractere', 82, '+$~', 33, 'd', 2, '!!!')

Après décomposition, il suffit de trier les tuples:
('A',2) < ('A', 10) < ('B', 1) < ('BA', 1) etc...

la méthode sort() des listes ou le fonction sorted() fait ça
parfaitement en utilisant le mot clef 'key':

data = ['R9', 'RC41', 'R1a', 'R10', 'CR1', 'R1b', 'C100', 'IN2P4',






'CR20-b', 'R20', 'Bidule35-t9', 'Bidule3a-t99', 'CR100']

print sorted(data, key=order) # Tri sans modification de data






['Bidule3a-t99', 'Bidule35-t9', 'C100', 'CR1', 'CR20-b', 'CR100',
'IN2P4', 'R1a', 'R1b', 'R9', 'R10', 'R20', 'RC41']

data.sort(key=order); print data # Ou tri en place de data:






['Bidule3a-t99', 'Bidule35-t9', 'C100', 'CR1', 'CR20-b', 'CR100',
'IN2P4', 'R1a', 'R1b', 'R9', 'R10', 'R20', 'RC41']

Ce critère de tri est d'usage assez général, mais il est possible
d'en fabiquer sur mesure pour tous les cas tordus.

Daniel
Avatar
NicolasP
Le 22/10/2010 15:25, Alain Ketterlin a écrit :
NicolasP writes:

Je cherche à faire une fonction de comparaison de chaine de caractères
pour un tri "alpha-numérique". Les chaines sont composées d'une partie
alphabétique(facultative) et d'une partie numérique.



def couple(s):
t = s.rstrip("0123456789")
n = s[len(t):]
return (t,int(n))

ensuite tu peux faire couple(s1)< couple(s2)

-- Alain.



J'utilise ça (merci google) :
e1 = re.findall(r'(d+|D+)', pin_name)

Pour moi la fonction couple est plus claire.

Merci

Nicolas
Avatar
NicolasP
Le 22/10/2010 16:46, Pierre Maurette a écrit :
NicolasP, le 10/22/2010 a écrit :
Bonjour,

Je cherche à faire une fonction de comparaison de chaine de caractères pour un tri "alpha-numérique".
Les chaines sont composées d'une partie alphabétique(facultative) et d'une partie numérique.
Soit :
"1" < "10"
"9" < "10"
"A1" < "A10"
"A9" < "A10"
"AA1" < "AA10"
"AA9" < "AA10"

"1" < "A1"
"A1" < "AA1"
"B1" < "AA1"
...

Clairement, il faut séparer la partie alphabétique et la partie numérique et traiter la partie numérique comme un nombre et non pas comme une chaine.

Comment faire cela simplement ?



Peut-être:
re.match('(D*)(.*)', chaine).groups()

ou plutôt:
pat = re.compile('(D*)(.*)')
#...
pat.match(chaine).groups()

un test:
for item in ('PIERRE', '128', 'PIERRE128', ''):
print pat.match(item).groups()




Une expression régulière marche bien mais je trouve la solution d'Alain Ketterlin plus lisible.

Nicolas
Avatar
NicolasP
On 22 oct, 14:46, NicolasP wrote:
Bonjour,

Je cherche à faire une fonction de comparaison de chaine de caractères pour un tri "alpha-numérique".
Les chaines sont composées d'une partie alphabétique(facultative) et d'une partie numérique.
Soit :
"1"< "10"
"9"< "10"
"A1"< "A10"
"A9"< "A10"
"AA1"< "AA10"
"AA9"< "AA10"

"1"< "A1"
"A1"< "AA1"
"B1"< "AA1"
...

Clairement, il faut séparer la partie alphabétique et la partie numérique et traiter la partie numérique comme un nombre et non pas comme une chaine.

Comment faire cela simplement ?

Nicolas



Bonsoir Nicolas,

On peut le faire avec une classe :

============ > import string

class alphanum:

def __init__(self,data):
self.alpha = data.rstrip(string.digits)
self.num = int(data[len(self.alpha):])

def __cmp__(self,autre):
return cmp((self.alpha,self.num),(autre.alpha,autre.num))

assert alphanum("1")<alphanum("10")
assert alphanum("9")<alphanum("10")
assert alphanum("A1")<alphanum("A10")
assert alphanum("A9")<alphanum("A10")
assert alphanum("AA1")<alphanum("AA10")
assert alphanum("AA9")<alphanum("AA10")
assert alphanum("1")<alphanum("A1")
assert alphanum("A1")<alphanum("AA1")
assert alphanum("B1")<alphanum("AA1")
================ >
mais le dernier test échoue : pouquoi B1 serait-il inférieur à AA1 ?
dans l'ordre alphabétique normal, B est après AA

A+
Pierre



Bonjour Pierre,

Le fait que B soit avant AA vient du contexte d'utilisation.
Je me fais un utilitaire pour manipuler des données de pattes de composants électroniques.
Les pattes sont numérotées purement numériquement pour les composants qui ont des pattes sur le pourtour.
Pour les composants qui ont des pattes sous la forme d'une grille répartie sous le boitier, la numérotation se fait sous la forme colonne/ligne avec des lettres pour les colonnes et des chiffres pour les lignes. Les lettres sont dans l'ordre A, B, C... AA, AB, AC.. BA, BB, BC...

Dans mon utilitaire, je veux les afficher dans une liste triée. Il me faut donc une fonction de comparaison adaptée à cet ordre.

Je suis arrivé à ça :
e1 = re.findall(r'(d+|D+)', self.pins[item1].pin_name)
e2 = re.findall(r'(d+|D+)', self.pins[item2].pin_name)
for a,b in zip(e1, e2) :
if len(a) > len(b) :
return 1
elif len(a) < len(b) :
return -1
else :
r = cmp(a, b)
if r :
return r

Je vais remplacer les expression régulières par rstrip() et int(). J'oublie toujours que la chaine passée à rstrip() est une liste de caractères à supprimer et non pas la chaine à supprimer.

Merci

Nicolas