将 Ruby 提交标题转换为 slug

56

我该如何在Ruby中将文章标题转换为slug?

标题可以包含任何字符,但我只希望slug允许[a-z0-9-_](是否应允许其他字符?)。

基本上:

  • 将所有字母转换为小写
  • 将空格转换为连字符
  • 删除多余字符

将以下与编程有关的内容从英语翻译成中文。如果标题超过N个单词,请删除多余的单词。 - Lassi
5个回答

108

这是Rails吗?(在Sinatra中可以运行)

string.parameterize

就是这样。对于更加复杂的slug处理,请参考ActsAsUrl。它可以执行以下操作:

"rock & roll".to_url => "rock-and-roll"
"$12 worth of Ruby power".to_url => "12-dollars-worth-of-ruby-power"
"10% off if you act now".to_url => "10-percent-off-if-you-act-now"
"kick it en Français".to_url => "kick-it-en-francais"
"rock it Español style".to_url => "rock-it-espanol-style"
"tell your readers 你好".to_url => "tell-your-readers-ni-hao"

这不是Rails,但看起来那个gem也可以在纯Ruby中使用。谢谢!我喜欢它将&转换为and的方式,但我希望它能将/和.转换为-。它分别将它们转换为斜杠和点。此外,在这种情况下,为了保持简单,我宁愿不需要额外的gems。因此,我更新了我的解决方案为slug = title.strip.downcase.gsub(/(&|&)/, ' and ').gsub(/[\s\.\/\\]/, '-').gsub(/[^\w-]/, '').gsub(/[-_]{2,}/, '-').gsub(/^[-_]/, '').gsub(/[-_]$/, '') - ma11hew28
它是否生成ASCII标识符,就像pandoc那样? - somenxavier
1
@somenxavier parameterize 就是这样做的。它来自于 ActiveSupport::Inflector。如果你查看源代码,你会看到注释 "# Replace accented chars with their ASCII equivalents"。 - Mark Thomas

89
slug = title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')

downcase 将其变为小写字母。 strip 用于确保没有前导或尾随的空格。第一个 gsub 用连字符替换空格。第二个 gsub 移除所有非字母、非破折号和非下划线的字符(请注意,这个集合与 \W 非常接近,但包括破折号,这就是为什么在这里进行拼写的原因)。


2
谢谢,Ben。我增加了一些复杂性来处理 . \ / 并删除连续的多个 - 并将其从末尾删除:slug = title.strip.downcase.gsub(/[\s\.\/\\]/, '-').gsub(/[^\w-]/, '').gsub(/[-_]{2,}/, '-').gsub(/^[-_]/, '').gsub(/[-_]$/, '')。我意识到这很难完美地实现,所以就停止了。此外,trgsub 更快,因此最好使用 tr(' ', '-') 而不是 gsub(' ', '-') - ma11hew28
1
@MattDiPasquale。有一个名为String#squeeze的Ruby方法,它将把所有传递字符的两个或多个序列转换为一个。因此,您可以将上述内容编写为slug = title.downcase.gsub('/[\s.\/_]/, ' ').squeeze(' ').strip.gsub(/[^\w-]/, '').tr(' ', '-')。这首先将所有空格、./_转换为空格。然后挤压空格(所有2个或更多空格的序列变成单个空格),然后删除空格(删除前导和尾随空格),然后将剩余的空格转换回破折号。 - Ben Lee
1
就gsub处理速度与tr而言,你实际上只是在谈论处理器周期——实际上是纳秒。除非你每秒创建数十万个帖子,否则这种速度差异将完全没有影响。你应该考虑的是个人风格和代码的清晰度。在这种情况下,我认为tr可能更好,但出于这两个原因,而不是因为它更快。 - Ben Lee
哦,这是针对普通 Ruby 的答案。如果您正在使用 Rails,则可以像 Mark Thomas 指出的那样执行 slug = title.parameterize。即使您没有使用 Rails,也可以通过执行以下操作从 active support gem 中获得相同的支持:require 'active_support'; $KCODE = 'UTF8'; - Ben Lee
1
哦,我刚刚注意到在我之前的评论中,我把东西放错顺序了。应该是:slug = title.downcase.gsub('/[\s.\/_]/, ' ').squeeze(' ').strip.tr(' ', '-').gsub(/[^\w-]/, '') - Ben Lee
显示剩余4条评论

7

to_slug是一个很棒的Rails插件,可以处理几乎所有内容,包括奇怪的字符,但它的实现非常简单。只需将其放在String上,您就可以轻松使用了。以下是源代码的压缩版本:

String.class_eval do
  def to_slug
    value = self.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n, '').to_s
    value.gsub!(/[']+/, '')
    value.gsub!(/\W+/, ' ')
    value.strip!
    value.downcase!
    value.gsub!(' ', '-')
    value
  end
end

4
@JamieRumbelow- 您的示例代码有误。您需要明确返回 value,因为当没有进行任何替换时(例如 "test".to_slug),.gsub! 会返回 nil。我已经为您修正了代码。 - Yarin

3

0

2
使用这个插件,你如何调用一个将你的字符串转换为短横线格式的方法? - Ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接