125 votes

Slugification des chaînes de caractères en Python

Je suis à la recherche de la meilleure façon de "slugifier" une chaîne de caractères. ce que "slug" est et ma solution actuelle est basée sur cette recette

Je l'ai un peu modifié pour :

s = 'String to slugify'

slug = unicodedata.normalize('NFKD', s)
slug = slug.encode('ascii', 'ignore').lower()
slug = re.sub(r'[^a-z0-9]+', '-', slug).strip('-')
slug = re.sub(r'[-]+', '-', slug)

Quelqu'un voit-il des problèmes avec ce code ? Il fonctionne bien, mais peut-être que quelque chose m'échappe ou que vous connaissez une meilleure méthode ?

1 votes

Travaillez-vous souvent avec l'unicode ? Si c'est le cas, le dernier re.sub pourrait être meilleur si vous l'entourez d'unicode(), c'est ce que fait django. De même, le [^a-z0-9]+ peut être raccourci en utilisant \w . voir django.template.defaultfilters, il est proche du vôtre, mais un peu plus raffiné.

0 votes

Les caractères unicode sont-ils autorisés dans les URL ? De plus, j'ai changé \w à a-z0-9 parce que \w comprend le caractère _ et les lettres majuscules. Les lettres sont mises en minuscules à l'avance, il n'y aura donc pas de lettres majuscules à faire correspondre.

0 votes

'_' est valide (mais c'est votre choix, vous l'avez demandé), l'unicode correspond aux caractères encodés en pourcentage.

189voto

kratenko Points 1960

Il existe un paquet python nommé python-slugify qui fait un assez bon travail de slugification :

pip install python-slugify

Ça marche comme ça :

from slugify import slugify

txt = "This is a test ---"
r = slugify(txt)
self.assertEquals(r, "this-is-a-test")

txt = "This -- is a ## test ---"
r = slugify(txt)
self.assertEquals(r, "this-is-a-test")

txt = 'C\'est déjà l\'été.'
r = slugify(txt)
self.assertEquals(r, "cest-deja-lete")

txt = 'Nín ho. W shì zhng guó rén'
r = slugify(txt)
self.assertEquals(r, "nin-hao-wo-shi-zhong-guo-ren")

txt = ''
r = slugify(txt)
self.assertEquals(r, "kompiuter")

txt = 'jaja---lol-méméméoo--a'
r = slugify(txt)
self.assertEquals(r, "jaja-lol-mememeoo-a")

Voir Autres exemples

Ce paquet fait un peu plus que ce que vous avez posté (jetez un coup d'œil à la source, c'est juste un fichier). Le projet est toujours actif (il a été mis à jour 2 jours avant ma réponse initiale, plus de neuf ans plus tard (dernière vérification le 2022-03-30), il est toujours mis à jour).

attention : Il existe un deuxième paquet, nommé slugify . Si vous avez les deux, vous risquez d'avoir un problème, car ils ont le même nom pour l'importation. Celui qui est juste nommé slugify n'a pas fait tout ce que j'ai vérifié rapidement : "Ich heiße" est devenu "ich-heie" (devrait être "ich-heisse" ), veillez donc à choisir le bon, lorsque vous utilisez la fonction pip o easy_install .

7 votes

python-slugify est sous licence MIT, mais il utilise Unidecode qui est sous licence GPL, donc il pourrait ne pas convenir à certains projets.

0 votes

@Rotareti Pourriez-vous m'expliquer pourquoi il n'est pas possible d'adapter tous les projets ? Ne pouvons-nous pas utiliser tout ce qui est sous licence MIT ou GPL et l'inclure dans un logiciel commercial ? Je pense que la seule restriction est de mettre la licence à côté des codes que nous développons. Est-ce que je me trompe ?

1 votes

@GhassemTofighi En bref : vous pouvez l'utiliser dans votre logiciel commercial, mais si vous l'utilisez, vous devez également ouvrir votre code. De toute façon IANAL et ce n'est pas un conseil juridique.

38voto

user1078810 Points 181

Installer le formulaire unidecode d'ici pour le support de l'unicode

pip install unidecode

# -*- coding: utf-8 -*-
import re
import unidecode

def slugify(text):
    text = unidecode.unidecode(text).lower()
    return re.sub(r'[\W_]+', '-', text)

text = u"My custom  "
print slugify(text)

>>> mon-custom-khello-vorld

1 votes

Salut, c'est un peu étrange mais il donne pour mon res comme ça "my-custom-ndud-d-d3-4-d2d3-4nd-d-"

1 votes

@derevo cela arrive quand on n'envoie pas de chaînes unicode. Remplacer slugify("My custom ") con slugify(u"My custom ") et cela devrait fonctionner.

11 votes

Je vous déconseille d'utiliser des noms de variables comme str . Cela cache la fonction str type.

12voto

dimka665 Points 46

Il existe un paquet python nommé awesome-slugify :

pip install awesome-slugify

Ça marche comme ça :

from slugify import slugify

slugify('one kožušcek')  # one-kozuscek

page github de awesome-slugify

4 votes

Beau paquet ! Mais attention, il est sous licence GPL.

1 votes

Attention : cela n'entraînera pas automatiquement l'utilisation de .lower() dans vos urls. Vous devrez exécuter slugify(text).lower() si vous le voulez.

8voto

Björn Lindqvist Points 3739

Le problème se situe au niveau de la ligne de normalisation ascii :

slug = unicodedata.normalize('NFKD', s)

Il s'appelle normalisation unicode qui ne décompose pas beaucoup de caractères en ascii. Par exemple, il supprimerait les caractères non ascii des chaînes de caractères suivantes :

Mørdag -> mrdag
Æther -> ther

Une meilleure façon de le faire est d'utiliser l'option unidecode qui essaie de traduire les chaînes de caractères en ascii. Donc si vous remplacez la ligne ci-dessus par :

import unidecode
slug = unidecode.unidecode(s)

Vous obtenez de meilleurs résultats pour les chaînes de caractères ci-dessus et pour de nombreux caractères grecs et russes également :

Mørdag -> mordag
Æther -> aether

8voto

Nick Presta Points 13298

Il fonctionne bien dans Django Je ne vois donc pas pourquoi ce ne serait pas une bonne fonction générale de slugification.

Avez-vous des problèmes avec elle ?

0 votes

Il est possible que dans certains cas, il s'agisse d'une bonne dose de paranoïa :-)

0 votes

Le code a été déplacé vers aquí .

20 votes

Pour les paresseux : from django.utils.text import slugify

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X