2009-03-31 8 views
33

slugifyフィルタがASCII以外の英数字を削除しないようにするにはどうすればよいですか? (私はDjango 1.0.2を使用しています)Django slugifyをUnicode文字列で正しく動作させるには?

cnprog.comには疑問のURLの中国語がありますので、私はそのコードを見ました。彼らは代わりに、彼らは

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

は、彼らがURLをslugifyingかそうでないパーマリンクを取得するには Questionモデルでこのメソッドを呼び出している、テンプレートに slugifyを使用していませんか?

答えて

85

は、それはラテン語ベースのアルファベットに適しています、さらにはギリシャのために合理的になります。

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

これは本当に素晴らしい小さなlibです。この回答は受け入れられるものでなければなりません。 –

+0

+1、素敵なlib!使いやすい。 – laike9m

+0

それは中国のピンインバージョン、超便利です!特にピンインが必要な場合。 –

10

djangoの定義はスラグを意味しますが、djangoのドキュメントでは明示的に述べていません。これはslugifyためdefaultfiltersの源である...あなたは値がエラーの場合には「無視」オプションで、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文字(または具体的には、英数字や$ -_!+!* '()以外の文字は、 %16進表記です。あなたのブラウザが送信した実際の生のGET要求を見ると(Firebugを使って)、中国文字は実際に送信される前にエンコードされていることがわかります。私はこれがなぜ唯一の理由でアスキーのみを主張しているのだろうと思う。

+1

Mozillaのunicode-slugifyに関するOpenSEOの答えにも注意してください。 – jnns

15

また、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'[?,:[email protected]#~`+=$%^&\\*()\[\]{}<>]','',txt, re.UNICODE) # remove some characters altogether 
     return txt 

は最後の正規表現置換を注意してください。

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 

私は:これは、次のPythonインタプリタセッションに示されるように、それらを再エンコードする間違って一部の非ASCII文字を取り除くかするかと思われる、より堅牢な表現r'\W'、との問題の回避策ですどのような問題が上にあるのか不明ですが、私はそれが "whatever is classified as alphanumeric in the Unicode character properties database"に由来すると推測しています。私は、Python 3.xがより良いUnicode処理に高い優先度を持っていると聞いたので、これはすでに修正されている可能性があります。または、おそらく正しいpythonの動作であり、私はユニコードや中国語を誤用しています。

現時点では、文字クラスを避け、明示的に定義された文字セットに基づいて置換を行うことをお勧めします。私はaskbotのQ &フォーラムのために採用しましたunidecodeと呼ばれるPythonのパッケージがあり

+1

+1のすべての仕事.. –

4

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

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

SlugHiFiが、それは国家の文字を置き換え違いで、定期的なslugifyのラッパーです英字のアルファベットと対応しています。

"Ą"の代わりに "Ł" => "L"の代わりに "A"が得られます。

+4

私はそれをHiFiスラッグではなくLoFiと呼んでいますが)! –

7

あなたは見たいかもしれません:それはあなたのための両方の「U」のの世話をする https://github.com/un33k/django-uuslug

ユニークでU、ユニコードでUです。

あなたは面倒な仕事をします。

8

https://github.com/mozilla/unicode-slugify サンプルコードはDjango 1.9はdjango.utils.text.slugifyallow_unicodeパラメータを導入しました。あなたがDjangoの< = 1.8を使用する場合は、次のことができpick up the code from Django 1.9

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

:ほとんどthe solution suggested by Jarret Hardieある

import re 
import unicodedata 

from django.utils import six 
from django.utils.encoding import force_text 
from django.utils.functional import allow_lazy 
from django.utils.safestring import SafeText, mark_safe 

def slugify_unicode(value): 
    value = force_text(value) 
    value = unicodedata.normalize('NFKC', value) 
    value = re.sub('[^\w\s-]', '', value, flags=re.U).strip().lower() 
    return mark_safe(re.sub('[-\s]+', '-', value, flags=re.U)) 
slugify_unicode = allow_lazy(slugify_unicode, six.text_type, SafeText) 

関連する問題