2009-11-01 44 views
31

Web框架,如Rails和Django的内置了支持,这是用来生成可读和SEO友好的URL“子弹”:Java代码/库生成蛞蝓(在漂亮的网址使用)

团状串典型地只包含的字符a-z0-9-和并因此可以在不写入URL转义(认为“富%20BA R“)。

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

一个平凡的蛞蝓功能将沿着线的东西:

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

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

我的问题:

  • 什么是生成Java的Django/Rails的类型蛞蝓最普遍的/实际的方法?

回答

34

Normalize您使用标准分解字符串:

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()是U + 0130(İ),而不是U + 0049(),所以你可能引入非latin1的字符返回到您的字符串,如果您使用String.toLowerCase()在土耳其语区域。

+1

看起来很有希望,但正常化似乎并没有工作:“Foobar的”被翻译成“FBR”,而不是预期的“FOOBAR”。你知道为什么吗? – knorv

+1

奇怪 - 当我通过这个方法把字符串'“f \ u00F3 \ u00F2b \ u00e2r''变成''foobar”'。您可能在源文件或数据文件中发生编码错误;请参阅http://illegalargumentexception.blogspot.com/2009/05/java-rough-guide-to-character-encoding.html – McDowell

+0

McDowell:你是绝对正确的 - 这是一个编码错误。感谢您的出色答案! – knorv

1

我已经通过@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("^-|-$",""); 
    } 
1

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(text).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); 
}