Pythonでの文字列スラッジ化


92

私は「スラグ」が何であるかを「slugify」文字列にする最良の方法を探しています、そして私の現在の解決策はこのレシピに基づいています

私はそれを少し変更しました:

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)

誰かがこのコードに問題を見つけましたか?それは正常に動作していますが、何かが足りないか、より良い方法を知っていますか?


あなたはユニコードをたくさん使っていますか?もしそうなら、それをunicode()でラップした方が最後のre.subの方が良いかもしれません。これがdjangoが行うことです。また、[^ a-z0-9] +を短縮して\ wを使用することもできます。django.template.defaultfiltersを参照してください。あなたに近いですが、もう少し洗練されています。
マイクラミレス

URLでUnicode文字を使用できますか?また、\ wには_文字と大文字が含まれているため、\ wをa-z0-9に変更しました。文字はあらかじめ小文字に設定されているため、一致する大文字はありません。
Zygimantas

'_'は有効です(ただし、選択したとおりです)。Unicodeはパーセントでエンコードされた文字です。
マイクラミレス

マイクありがとう。さて、私は間違った質問をしました。「az」、「0-9」、および「-」以外のすべての文字を既に置き換えた場合、それをUnicode文字列にエンコードして戻す理由はありますか?
Zygimantas

djangoの場合、互換性のために、すべての文字列をUnicodeオブジェクトとして持つことが重要だと私は信じています。これが必要なら、それはあなたの選択です。
マイクラミレス

回答:


144

という名前のpythonパッケージがありpython-slugify、slugifyingのかなり良い仕事をします:

pip install python-slugify

このように動作します:

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 hǎo. Wǒ shì zhōng 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")

その他の例見る

このパッケージはあなたが投稿したものよりも少しだけ機能します(ソースを見てください、それはただ1つのファイルです)。プロジェクトはまだアクティブです(最初に回答する2日前に更新されましたが、7年以上経過しました(最後にチェックした2020-06-30)。それでも更新されます)。

注意:という名前の2番目のパッケージがありますslugify。両方を持っている場合、インポート用に同じ名前が付いているため、問題が発生する可能性があります。名前slugifyが付けられたものは、私が簡単にチェックしたすべてを実行しませんでした:に"Ich heiße"なった"ich-heie"(はずです"ich-heisse")ので、pipまたはを使用するときは、正しいものを選択してくださいeasy_install


6
python-slugifyはMITでUnidecodeライセンスされていますが、GPLでライセンスされているを使用しているため、一部のプロジェクトには適合しない可能性があります。
ロタレティ2017

@Rotaretiなぜすべてのプロジェクトに対応できないのか説明してください。MITまたはGPLライセンスの下で何も使用して、商用ソフトウェアに含めることはできませんか?私が開発するコード以外にライセンスを置くことが唯一の制限だと思います。私が間違っている?
Ghassem Tofighi

1
@GhassemTofighiつまり、商用ソフトウェアで使用できますが、使用する場合は、コードもオープンソースにする必要があります。とにかくIANALとこれは法的助言ではありません。
ロタレッティ

@GhassemTofighiは多分そのトピックについてsoftwareengineering.stackexchange.com/q/47032/71504
ご覧ください

1
@Rotareti python-slugifyはデフォルトでtext-unidecodeGPLライセンスの代わりにArtistic License'd になり、Unidecodeライセンスの問題に対処しています。github.com/un33k/python-slugify/commit/...
Emilien

31

ユニコードサポートのためにここからユニコードフォームインストールしてください

pipインストール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)

>>> my-custom-khello-vorld


1
こんにちは、少し奇妙ですが、「my-custom-ndud-d-d3-4-d2d3-4nd-d-」のような私の解像度を与えます
derevo

1
@derevoは、Unicode文字列を送信しないときに発生しました。元に戻しslugify("My custom хелло ворлд")slugify(u"My custom хелло ворлд")、それが動作するはずです。
kratenko

9
のような変数名を使用しないことをお勧めしますstr。これにより、組み込みstrタイプが非表示になります。
Crodjer 14

2
unidecodeはGPLであり、一部には適さない場合があります。
Jorge Leitao

relugifyingまたはdeslugifyingについてはどうですか。
Ryan Chou

11

awesome-slugifyという名前のpythonパッケージがあります:

pip install awesome-slugify

このように動作します:

from slugify import slugify

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

awesome-slugify githubページ


2
素敵なパッケージ!しかし、注意してください、それはGPLの下でライセンスされています。
ロタレティ2017

1
ヘッドアップ:これは自動的にあなたのURLを.lower()しません。必要な場合は実行する必要がありますslugify(text).lower()
Kalob Taulien


6

問題は、ASCII正規化行にあります。

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

これはUnicode正規化と呼ばれ、多くの文字をASCIIに分解しません。たとえば、次の文字列から非ASCII文字を削除します。

Mørdag -> mrdag
Æther -> ther

これを行うためのより良い方法は、文字列をASCIIに文字変換しようとするunidecodeモジュールを使用することです。したがって、上記の行を次のように置き換えた場合:

import unidecode
slug = unidecode.unidecode(s)

上記の文字列と、多くのギリシャ語とロシア語の文字についても、より良い結果が得られます。

Mørdag -> mordag
Æther -> aether

5
def slugify(value):
    """
    Converts to lowercase, removes non-word characters (alphanumerics and
    underscores) and converts spaces to hyphens. Also strips leading and
    trailing whitespace.
    """
    value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
    value = re.sub('[^\w\s-]', '', value).strip().lower()
    return mark_safe(re.sub('[-\s]+', '-', value))
slugify = allow_lazy(slugify, six.text_type)

これはdjango.utils.textにあるslugify関数ですこれで十分でしょう。



2

GitHubのいくつかのオプション:

  1. https://github.com/dimka665/awesome-slugify
  2. https://github.com/un33k/python-slugify
  3. https://github.com/mozilla/unicode-slugify

それぞれがそのAPIに対してわずかに異なるパラメーターをサポートしているので、何を好むかを理解するために一読する必要があります。

特に、非ASCII文字を処理するために提供されるさまざまなオプションに注意してください。Pydannyは、これらのslugifyを実行するライブラリのUnicode処理の違いを示す非常に役立つブログ投稿を作成しましたこのブログの投稿は、Mozillaのunicode-slugifyはDjango固有ではなくなっます。

また、現在awesome-slugifyGPLv3であることに注意してください。作者がMIT / BSDとしてリリースすることを好むという未解決の問題があります。 24


1

最終行を次のように変更することを検討してください

slug=re.sub(r'--+',r'-',slug)

パターン[-]+はと同じであり-+、ハイフンが1つだけの場合でも、2つ以上の場合でも一致する必要はありません。

しかし、もちろん、これはかなりマイナーです。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.