web-dev-qa-db-ja.com

Django slugifyをUnicode文字列で正しく機能させる方法は?

slugifyフィルターが非ASCII英数字を削除しないようにするにはどうすればよいですか? (私はDjango 1.0.2)を使用しています

cnprog.com 質問のURLに漢字があるので、それらのコードを調べました。テンプレートでslugifyを使用しておらず、代わりにQuestionモデルでこのメソッドを呼び出してパーマリンクを取得しています

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

彼らはURLをスラッグ化しているかどうか?

37
Imran

私がaskbotQ&Aフォーラムに採用したpythonパッケージ nidecode があります。これはラテン語ベースのアルファベットでうまく機能し、ギリシャ語でも妥当に見えます。

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

それはアジアの言語で奇妙なことをします:

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

これは意味がありますか?

Askbotでは、次のようにスラッグを計算します。

from unidecode import unidecode
from Django.template import defaultfilters
slug = defaultfilters.slugify(unidecode(input_text))
93
Evgeny

Mozilla Webサイトチームは実装に取り​​組んでいます: https://github.com/mozilla/unicode-slugify サンプルコード http://davedash.com/2011/03/ 24/how-we-slug-at-mozilla /

23
Open SEO

また、slugifyのDjangoバージョンはre.UNICODEフラグを使用しないため、非ASCIIに関連するため、\w\sの意味を理解しようとさえしません。文字。

このカスタムバージョンは私にとってうまく機能しています:

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

最後の正規表現の置換に注意してください。これは、次のpythonに示すように、一部の非ASCII文字を削除するか、誤って再エンコードするように見える、より堅牢な式r'\W'の問題の回避策です。 =通訳セッション:

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

上記の問題が何であるかはわかりませんが、「 nicode文字プロパティデータベースで英数字として分類されているものは何でも 」とその実装方法に起因していると思います。 python 3.xはUnicodeの処理を改善することを優先していると聞いたので、これはすでに修正されている可能性があります。または、正しいかもしれませんpython 、および私はユニコードおよび/または中国語を誤用しています。

今のところ、回避策は文字クラスを避け、明示的に定義された文字セットに基づいて置換を行うことです。

15
Arthur Hebert

Django> = 1.9の場合、 Django.utils.text.slugify にはallow_unicodeパラメータ:

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

Django <= 1.8(2018年4月以降は使用しないでください)を使用する場合、次のことができます Django 1.9 からコードを取得します=。

13
Antoine Pinsard

Django docsはこれを明示的に述べていませんが、Djangoのslugの定義はasciiを意味するのではないかと思います。これがslugifyのdefaultfiltersのソースです...値がわかりますエラーの場合は「ignore」オプションを使用して、ASCIIに変換されています。

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))

これに基づくと、cnprog.comは公式のslugify関数を使用していないと思います。別の動作が必要な場合は、上記のDjangoスニペットを適応させることをお勧めします。

ただし、URLのRFCには、ASCII以外の文字(より具体的には、英数字と$ -_。+!* '()以外のもの)は%hex表記を使用してエンコードする必要があると記載されています。 。ブラウザが送信する実際の生のGETリクエストを見ると(たとえば、Firebugを使用して)、送信される前に漢字が実際にエンコードされていることがわかります...ブラウザはディスプレイ上できれいに見えるようにします。これが、slugifyがASCIIのみを主張する理由だと思います。

9
Jarret Hardie

あなたは見たいかもしれません: https://github.com/un33k/Django-uuslug

それはあなたのために両方の「U」の世話をします。 [〜#〜] u [〜#〜]一意で[〜#〜] u [〜# Unicodeでは〜]

それはあなたのための仕事を手間をかけずに行います。

8
un33k

これは私が使用するものです:

http://trac.Django-fr.org/browser/site/trunk/djangofr/links/slughifi.py

SlugHiFiは、通常のslugifyのラッパーですが、国別の文字を対応する英語のアルファベットに置き換えるという違いがあります。

したがって、「Ą」の代わりに「Ł」=>「L」の代わりに「A」を取得します。

4
mhl666

スラッグにASCII文字のみを許可することに興味があります。これが、同じ文字列に対して使用可能なツールのいくつかをベンチマークしようとした理由です。

  • nicode 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'
    
  • Awesome 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 with nidecode

    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'
    
1
raratiru