44

诸如 Rails 和 Django 之类的 Web 框架内置了对“slugs”的支持,这些“slugs”用于生成可读且对 SEO 友好的 URL:

一个 slug 字符串通常只包含 characters a-z0-9因此-可以在没有 URL 转义的情况下编写(想想“foo%20bar”)。

我正在寻找一个 Java slug 函数,它给定任何有效的 Unicode 字符串都将返回一个 slug 表示(a-z0-9-

一个微不足道的 slug 函数将类似于以下内容:

return input.toLowerCase().replaceAll("[^a-z0-9-]", "");

但是,此实现不会处理国际化和重音符号 ( ë> e)。解决这个问题的一种方法是枚举所有特殊情况,但这不是很优雅。我正在寻找更深思熟虑和一般的东西。

我的问题:

  • 在 Java 中生成 Django/Rails 类型 slug 的最通用/实用的方法是什么?
4

4 回答 4

53

使用规范分解规范化您的字符串:

  private static final Pattern NONLATIN = Pattern.compile("[^\\w-]");
  private static final Pattern WHITESPACE = Pattern.compile("[\\s]");

  public static String toSlug(String input) {
    String nowhitespace = WHITESPACE.matcher(input).replaceAll("-");
    String normalized = Normalizer.normalize(nowhitespace, Form.NFD);
    String slug = NONLATIN.matcher(normalized).replaceAll("");
    return slug.toLowerCase(Locale.ENGLISH);
  }

不过,这仍然是一个相当幼稚的过程。它不会对 s-sharp(ß - 用于德语)或任何非拉丁字母(希腊语、西里尔文、CJK 等)做任何事情。

更改字符串的大小写时要小心。大写和小写形式取决于字母表。在土耳其语中,U+0069 ( i ) 的大写是 U+0130 ( İ ),而不是 U+0049 ( IString.toLowerCase() ),因此如果您在土耳其语语言环境下使用,您可能会在字符串中引入非 latin1 字符。

于 2009-11-01T14:08:58.813 回答
16

http://search.maven.org/#search|ga|1|slugify

这是 GitHub 存储库,可以查看代码及其用法:

https://github.com/slugify/slugify

于 2012-07-17T17:42:32.567 回答
10

McDowel 的命题几乎可行,但在这种情况下,Hello World !!它返回hello-world--(注意--字符串末尾的 )而不是hello-world.

固定版本可能是:

private static final Pattern NONLATIN = Pattern.compile("[^\\w-]");
private static final Pattern WHITESPACE = Pattern.compile("[\\s]");
private static final Pattern EDGESDHASHES = Pattern.compile("(^-|-$)");

public static String toSlug(String input) {
    String nowhitespace = WHITESPACE.matcher(input).replaceAll("-");
    String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD);
    String slug = NONLATIN.matcher(normalized).replaceAll("");
    slug = EDGESDHASHES.matcher(slug).replaceAll("");
    return slug.toLowerCase(Locale.ENGLISH);
}
于 2016-05-31T17:40:26.543 回答
5

我已经扩展了@McDowell 的答案,包括将标点符号转义为连字符并删除重复和前导/尾随连字符。

  private static final Pattern NONLATIN = Pattern.compile("[^\\w_-]");  
  private static final Pattern SEPARATORS = Pattern.compile("[\\s\\p{Punct}&&[^-]]");  

  public static String makeSlug(String input) {  
    String noseparators = SEPARATORS.matcher(input).replaceAll("-");
    String normalized = Normalizer.normalize(noseparators, Form.NFD);
    String slug = NONLATIN.matcher(normalized).replaceAll("");
    return slug.toLowerCase(Locale.ENGLISH).replaceAll("-{2,}","-").replaceAll("^-|-$","");
  }
于 2015-11-20T16:21:11.153 回答