Me gustaría saber si hay algo similar a la función PHP natsort en Python?
l = ['image1.jpg', 'image15.jpg', 'image12.jpg', 'image3.jpg'] l.sort()
da:
['image1.jpg', 'image12.jpg', 'image15.jpg', 'image3.jpg']
pero me gustaría conseguir:
['image1.jpg', 'image3.jpg', 'image12.jpg', 'image15.jpg']
ACTUALIZAR
Base de soluciones en este enlace.
def try_int(s): "Convert to integer if possible." try: return int(s) except: return s def natsort_key(s): "Used internally to get a tuple by which s is sorted." import re return map(try_int, re.findall(r'(\d+|\D+)', s)) def natcmp(a, b): "Natural string comparison, case sensitive." return cmp(natsort_key(a), natsort_key(b)) def natcasecmp(a, b): "Natural string comparison, ignores case." return natcmp(a.lower(), b.lower()) l.sort(natcasecmp);
De mi respuesta al algoritmo de clasificación natural :
import re def natural_key(string_): """See http://www.codinghorror.com/blog/archives/001018.html""" return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_)]
Ejemplo:
>>> L = ['image1.jpg', 'image15.jpg', 'image12.jpg', 'image3.jpg'] >>> sorted(L) ['image1.jpg', 'image12.jpg', 'image15.jpg', 'image3.jpg'] >>> sorted(L, key=natural_key) ['image1.jpg', 'image3.jpg', 'image12.jpg', 'image15.jpg']
Para admitir cadenas de caracteres Unicode, se debe usar .isdigit()
lugar de .isdigit()
. Ver ejemplo en el comentario de @phihag . Relacionado: Cómo revelar la propiedad del valor numérico de Unicodes .
.isdigit()
también puede fallar (valor devuelto que no es aceptado por int()
) para un bytestring en Python 2 en algunas configuraciones regionales, por ejemplo, ‘\ xb2’ (‘²’) en la configuración regional cp1252 en Windows .
Puede consultar la biblioteca natsort de terceros en PyPI:
>>> import natsort >>> l = ['image1.jpg', 'image15.jpg', 'image12.jpg', 'image3.jpg'] >>> natsort.natsorted(l) ['image1.jpg', 'image3.jpg', 'image12.jpg', 'image15.jpg']
Revelación completa, soy el autor.
Esta función se puede usar como el argumento key=
para sorted
en Python 2.xy 3.x:
def sortkey_natural(s): return tuple(int(part) if re.match(r'[0-9]+$', part) else part for part in re.split(r'([0-9]+)', s))