2009-11-01 41 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); 
}