fonction de comparaison

Le
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
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
NicolasP
Le #22705311
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.
Alain Ketterlin
Le #22705301
NicolasP
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.
Pierre Maurette
Le #22705681
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
Pierre Quentel
Le #22707001
On 22 oct, 14:46, NicolasP
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
Daniel Gallavardin
Le #22707091
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
NicolasP
Le #22716551
Le 22/10/2010 15:25, Alain Ketterlin a écrit :
NicolasP
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
NicolasP
Le #22716541
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
NicolasP
Le #22716631
On 22 oct, 14:46, 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



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
Publicité
Poster une réponse
Anonyme