Python中的字符串slugification
Posted
技术标签:
【中文标题】Python中的字符串slugification【英文标题】:String slugification in Python 【发布时间】:2011-07-31 06:00:22 【问题描述】:我正在寻找“slugify”字符串what "slug" is的最佳方法,我目前的解决方案是基于this recipe
我稍微改了一下:
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 吗?如果是这样,如果将 unicode() 包裹在最后一个 re.sub 可能会更好,这就是 django 所做的。此外, [^a-z0-9]+ 可以缩短为使用 \w 。请参阅 django.template.defaultfilters,它与您的接近,但更精致。 URL 中是否允许使用 unicode 字符?另外,我已将 \w 更改为 a-z0-9,因为 \w 包含 _ 字符和大写字母。字母是预先设置为小写的,所以不会有大写字母匹配。 '_' 是有效的(但你的选择,你确实问过),unicode 是百分比编码的字符。 谢谢迈克。好吧,我问了一个错误的问题。如果我们已经替换了除“a-z”、“0-9”和“-”之外的所有字符,是否有任何理由将其编码回 unicode 字符串? 对于 django,我相信将所有字符串都作为 unicode 对象以实现兼容性对他们来说很重要。如果您愿意,这是您的选择。 【参考方案1】:有一个名为 python-slugify
的 python 包,它在 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")
见More examples
这个包比你发布的要多一点(看看源代码,它只是一个文件)。该项目仍然有效(在我最初回答前 2 天更新,七年后(最后一次检查 2020-06-30),它仍然在更新)。
小心:还有第二个包,名为slugify
。如果您同时拥有它们,您可能会遇到问题,因为它们具有相同的导入名称。刚刚命名为slugify
的那个并没有完成我快速检查的所有操作:"Ich heiße"
变成了"ich-heie"
(应该是"ich-heisse"
),所以在使用pip
或easy_install
时一定要选择正确的那个.
【讨论】:
python-slugify
在 MIT 下获得许可,但它使用在 GPL 下获得许可的Unidecode
,因此它可能不适合某些项目。
@Rotareti 你能解释一下为什么它不能适合所有项目吗?我们不能在 MIT 或 GPL 许可下使用任何东西并将它们包含在商业软件中吗?我认为唯一的限制是将许可证放在我们开发的代码之外。我错了吗?
@GhassemTofighi 简而言之:你可以在你的商业软件中使用它,但如果你使用它,你也必须开源你的代码。无论如何,IANAL,这不是法律建议。
@GhassemTofighi 或许可以看看 softwareengineering.stackexchange.com/q/47032/71504 关于该主题
@Rotareti python-slugify
现在默认为艺术许可的text-unidecode
,而不是 GPL 许可的Unidecode
,解决了您的许可问题。 github.com/un33k/python-slugify/commit/…【参考方案2】:
安装 unidecode 表单 from here 以获得 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)
>>> my-custom-khello-vorld
【讨论】:
嗨,它有点奇怪,但它为我的资源提供了“my-custom-ndud-d-d3-4-d2d3-4nd-d-” @derevo 发生在您不发送 unicode 字符串时。将slugify("My custom хелло ворлд")
替换为slugify(u"My custom хелло ворлд")
,它应该可以工作。
我建议不要使用像str
这样的变量名。这隐藏了内置的 str
类型。
unidecode 是 GPL,可能不适合某些人。
那reslugifying或deslugifying怎么样。【参考方案3】:
有一个名为awesome-slugify的python包:
pip install awesome-slugify
像这样工作:
from slugify import slugify
slugify('one kožušček') # one-kozuscek
awesome-slugify github page
【讨论】:
不错的包装!但要小心,它是在 GPL 下获得许可的。 注意:这不会自动 .lower() 你的网址。如果需要,您需要运行slugify(text).lower()
。【参考方案4】:
它在 Django 中运行良好,所以我不明白为什么它不是一个好的通用 slugify 函数。
你有什么问题吗?
【讨论】:
有可能,在某些情况下,这是一种健康的偏执狂:-) 代码已移至here。 懒人:from django.utils.text import slugify
【参考方案5】:
问题在于 ascii 规范化行:
slug = unicodedata.normalize('NFKD', s)
它被称为unicode normalization,它不会将大量字符分解为ascii。例如,它会从以下字符串中去除非 ascii 字符:
Mørdag -> mrdag
Æther -> ther
一个更好的方法是使用unidecode 模块尝试将字符串音译为ascii。因此,如果您将上述行替换为:
import unidecode
slug = unidecode.unidecode(s)
对于上述字符串以及许多希腊语和俄语字符,您可以获得更好的结果:
Mørdag -> mordag
Æther -> aether
【讨论】:
【参考方案6】: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 函数 这应该可以满足您的要求。
【讨论】:
【参考方案7】:Unidecode 不错;但是,请注意:unidecode 是 GPL。如果此许可证不适合,请使用this one
【讨论】:
【参考方案8】:GitHub 上的几个选项:
-
https://github.com/dimka665/awesome-slugify
https://github.com/un33k/python-slugify
https://github.com/mozilla/unicode-slugify
每个 API 支持的参数略有不同,因此您需要仔细研究以确定您喜欢什么。
特别要注意它们为处理非 ASCII 字符提供的不同选项。 Pydanny 写了一篇非常有用的博文,说明了这些 slugify 库中的一些 unicode 处理差异:http://www.pydanny.com/awesome-slugify-human-readable-url-slugs-from-any-string.html 这篇博文有些过时了,因为 Mozilla 的 unicode-slugify
不再是 Django 特定的。
还请注意,目前awesome-slugify
是 GPLv3,尽管有一个未解决的问题,作者说他们更愿意以 MIT/BSD 的形式发布,只是不确定其合法性:https://github.com/dimka665/awesome-slugify/issues/24
【讨论】:
【参考方案9】:你可以考虑把最后一行改成
slug=re.sub(r'--+',r'-',slug)
因为模式[-]+
与-+
没有什么不同,而且你并不关心只匹配一个连字符,只匹配两个或更多。
但是,当然,这是非常轻微的。
【讨论】:
【参考方案10】:另一个选项是boltons.strutils.slugify
。 Boltons 还有很多其他有用的功能,并且是在 BSD
许可证下分发的。
【讨论】:
【参考方案11】:以您的示例为例,一种快速的方法可能是:
s = 'String to slugify'
slug = s.replace(" ", "-").lower()
【讨论】:
以上是关于Python中的字符串slugification的主要内容,如果未能解决你的问题,请参考以下文章