Question

Que puis-je faire pour éviter que le filtre slugify de décapage des caractères alphanumériques non-ASCII? (J'utilise Django 1.0.2)

cnprog.com a des caractères chinois dans les URL de question, alors j'ai regardé dans leur code. Ils n'utilisent pas slugify dans les modèles, au lieu qu'ils appellent cette méthode dans le modèle de Question pour obtenir permaliens

def get_absolute_url(self):
    return '%s%s' % (reverse('question', args=[self.id]), self.title)

Sont-ils slugifying les URL ou non?

Était-ce utile?

La solution

Il y a un paquet python appelé unidecode que j'ai adopté pour le askbot Q & A forum, il fonctionne bien pour les alphabets latin et semble encore raisonnable grec:

>>> import unidecode
>>> from unidecode import unidecode
>>> unidecode(u'διακριτικός')
'diakritikos'

Il fait quelque chose de bizarre avec les langues asiatiques:

>>> unidecode(u'影師嗎')
'Ying Shi Ma '
>>> 

Est-ce sens?

En askbot on calcule les limaces comme ceci:

from unidecode import unidecode
from django.template import defaultfilters
slug = defaultfilters.slugify(unidecode(input_text))

Autres conseils

L'équipe du site Mozilla travaille sur une mise en œuvre: https://github.com/mozilla/unicode-slugify exemple de code à http://davedash.com/2011/03/24/how-we-slug -at-mozilla /

En outre, la version Django de slugify ne pas utiliser le drapeau re.UNICODE, il serait même pas essayer de comprendre le sens de \w\s en ce qui concerne les caractères non-ascii.

Cette version personnalisée fonctionne bien pour moi:

def u_slugify(txt):
        """A custom version of slugify that retains non-ascii characters. The purpose of this
        function in the application is to make URLs more readable in a browser, so there are 
        some added heuristics to retain as much of the title meaning as possible while 
        excluding characters that are troublesome to read in URLs. For example, question marks 
        will be seen in the browser URL as %3F and are thereful unreadable. Although non-ascii
        characters will also be hex-encoded in the raw URL, most browsers will display them
        as human-readable glyphs in the address bar -- those should be kept in the slug."""
        txt = txt.strip() # remove trailing whitespace
        txt = re.sub('\s*-\s*','-', txt, re.UNICODE) # remove spaces before and after dashes
        txt = re.sub('[\s/]', '_', txt, re.UNICODE) # replace remaining spaces with underscores
        txt = re.sub('(\d):(\d)', r'\1-\2', txt, re.UNICODE) # replace colons between numbers with dashes
        txt = re.sub('"', "'", txt, re.UNICODE) # replace double quotes with single quotes
        txt = re.sub(r'[?,:!@#~`+=$%^&\\*()\[\]{}<>]','',txt, re.UNICODE) # remove some characters altogether
        return txt

Notez la dernière substitution regex. Ceci est une solution à un problème avec le r'\W' d'expression plus robuste, qui semble soit dépouiller certains caractères non-ascii ou les ré-encoder de façon incorrecte, comme illustré dans la session de l'interpréteur python suivant:

Python 2.5.1 (r251:54863, Jun 17 2009, 20:37:34) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> # Paste in a non-ascii string (simplified Chinese), taken from http://globallives.org/wiki/152/
>>> str = '您認識對全球社區感興趣的中國攝影師嗎'
>>> str
'\xe6\x82\xa8\xe8\xaa\x8d\xe8\xad\x98\xe5\xb0\x8d\xe5\x85\xa8\xe7\x90\x83\xe7\xa4\xbe\xe5\x8d\x80\xe6\x84\x9f\xe8\x88\x88\xe8\xb6\xa3\xe7\x9a\x84\xe4\xb8\xad\xe5\x9c\x8b\xe6\x94\x9d\xe5\xbd\xb1\xe5\xb8\xab\xe5\x97\x8e'
>>> print str
您認識對全球社區感興趣的中國攝影師嗎
>>> # Substitute all non-word characters with X
>>> re_str = re.sub('\W', 'X', str, re.UNICODE)
>>> re_str
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\xa3\xe7\x9a\x84\xe4\xb8\xad\xe5\x9c\x8b\xe6\x94\x9d\xe5\xbd\xb1\xe5\xb8\xab\xe5\x97\x8e'
>>> print re_str
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX?的中國攝影師嗎
>>> # Notice above that it retained the last 7 glyphs, ostensibly because they are word characters
>>> # And where did that question mark come from?
>>> 
>>> 
>>> # Now do the same with only the last three glyphs of the string
>>> str = '影師嗎'
>>> print str
影師嗎
>>> str
'\xe5\xbd\xb1\xe5\xb8\xab\xe5\x97\x8e'
>>> re.sub('\W','X',str,re.U)
'XXXXXXXXX'
>>> re.sub('\W','X',str)
'XXXXXXXXX'
>>> # Huh, now it seems to think those same characters are NOT word characters

Je ne suis pas sûr que le problème est au-dessus, mais je devine qu'il vient de « tout est classé comme alphanumérique dans la base de données des propriétés de caractères Unicode , » et comment cela est mis en œuvre. Je l'ai entendu dire que 3.x python a une priorité sur une meilleure gestion des unicode, donc cela peut être fixé déjà. Ou, peut-être est un comportement python correct, et j'utilise à mauvais escient unicode et / ou la langue chinoise.

Pour l'instant, une autre solution consiste à éviter les classes de caractères, et faire des substitutions basées sur les jeux de caractères explicitement définis.

Je suis la définition de django peur des limaces signifie ascii, bien que les documents django ne précisent pas explicitement. Ceci est la source des defaultfilters pour la slugify ... vous pouvez voir que les valeurs sont converties en ascii, avec l'option « ignorer » en cas d'erreur:

import unicodedata
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
return mark_safe(re.sub('[-\s]+', '-', value))

Sur cette base, je suppose que cnprog.com n'utilise une fonction slugify officielle. Vous pouvez adapter les django extrait ci-dessus si vous voulez un comportement différent.

Cela dit, cependant, le RFC pour les URL ne état que les caractères non-ascii-nous (ou, plus précisément, autre chose que les caractères alphanumériques et $ -_. +! * ()) Doivent être codées en utilisant la % notation hexadécimale. Si vous regardez à la demande GET brute réelle que votre navigateur envoie (par exemple, en utilisant Firebug), vous verrez que les caractères chinois sont en fait encodés avant d'être envoyé ... juste le navigateur lui donne une apparence assez à l'écran. Je soupçonne que c'est pourquoi slugify insiste sur ascii que, FWIW.

Django> = 1.9 , django.utils.text.slugify a un paramètre allow_unicode:

>>> slugify("你好 World", allow_unicode=True)
"你好-world"

Si vous utilisez Django <= 1.8 (qui vous ne devriez pas depuis Avril 2018), vous pouvez chercher le code de Django 1.9 .

Vous pouvez consulter: https://github.com/un33k/django-uuslug

Il prendra soin des deux « U » s pour vous. U unique et U en Unicode.

Il fera le travail pour vous sans tracas.

Voici ce que j'utilise:

http: //trac.django-fr. org / navigateur / site / trunk / djangofr / liens / slughifi.py

SlugHiFi est une enveloppe pour slugify régulière, avec une différence qu'il remplace les caractères nationaux avec leurs homologues de l'alphabet anglais.

Ainsi, au lieu de « ã » vous obtenez « A », au lieu de « l » => « L », et ainsi de suite.

Je suis intéressé à laisser des caractères ASCII dans la limace c'est pourquoi j'ai essayé de comparer certains des outils disponibles pour la même chaîne:

  • Unicode slugify :

    In [5]: %timeit slugify('Παίζω τρέχω %^&*@# και γ%^(λώ la fd/o', only_ascii=True)
    37.8 µs ± 86.7 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    'paizo-trekho-kai-glo-la-fdo'
    
  • Django Uuslug :

    In [3]: %timeit slugify('Παίζω τρέχω %^&*@# και γ%^(λώ la fd/o')
    35.3 µs ± 303 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    'paizo-trekho-kai-g-lo-la-fd-o'
    
  • Impressionnant slugify:

    In [3]: %timeit slugify('Παίζω τρέχω %^&*@# και γ%^(λώ la fd/o')
    47.1 µs ± 1.94 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    'Paizo-trekho-kai-g-lo-la-fd-o'
    
  • Python slugify :

    In [3]: %timeit slugify('Παίζω τρέχω %^&*@# και γ%^(λώ la fd/o')
    24.6 µs ± 122 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    'paizo-trekho-kai-g-lo-la-fd-o'
    
  • django.utils.text.slugify avec href="https://github.com/avian2/unidecode" rel="nofollow noreferrer"> Unidecode :

    In [15]: %timeit slugify(unidecode('Παίζω τρέχω %^&*@# και γ%^(λώ la fd/o'))
    36.5 µs ± 89.7 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    'paizo-trekho-kai-glo-la-fdo'
    
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top