The method should allows only "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" chars in URI strings.
- 
                    3This sounds like a terrible idea. Consider [encoding the URL](http://download.oracle.com/javase/1.5.0/docs/api/java/net/URLEncoder.html) instead. – moinudin Jan 02 '11 at 23:19
- 
                    @marcog: It sounds a lot like what SO does to generate SEO-friendly URLs from titles. Mind you, I'd be very tempted to just replace all non-alnum char sequences with a single hyphen; same general effect (if perhaps slightly different in edge cases) but easier to understand. – Donal Fellows Jan 02 '11 at 23:27
- 
                    @Donal Oh, right. Surely you'd generate a random string from the set of allowed characters though? – moinudin Jan 02 '11 at 23:28
- 
                    1@marcog: What SO does is put that part (which actually *doesn't matter*) on the end of the URL; the path fragment before is an ID which is what actually locates the question. It's safe to use user input for this because the sanitization is defined in terms of a severe whitelist of characters. (Random string? Where did that come from?) – Donal Fellows Jan 03 '11 at 20:01
- 
                    @Donal Okay, I see what you're referring to. I thought you meant the ID, e.g. 4581025 for this question. Thanks for clarifying! – moinudin Jan 03 '11 at 20:09
3 Answers
This is what the general consensus is:
- Lowercase the string. - string = string.toLowerCase();
- Normalize all characters and get rid of all diacritical marks (so that e.g. é, ö, à becomes e, o, a). - string = Normalizer.normalize(string, Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
- Replace all remaining non-alphanumeric characters by - -and collapse when necessary.- string = string.replaceAll("[^\\p{Alnum}]+", "-");
So, summarized:
public static String toPrettyURL(String string) {
    return Normalizer.normalize(string.toLowerCase(), Form.NFD)
        .replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
        .replaceAll("[^\\p{Alnum}]+", "-");
}
 
    
    - 1,082,665
- 372
- 3,610
- 3,555
- 
                    4Also recommend removing leading and trailing punctuation. // remove trailing punctuation .replaceAll("[^a-z0-9]+$", "") // remove leading punctuation .replaceAll("^[^a-z0-9]+", ""); – Jason Thrasher May 06 '12 at 18:24
The following regex will do the same thing as your algorithm. I'm not aware of libraries for doing this type of thing.
String s = input
.replaceAll(" ?- ?","-") // remove spaces around hyphens
.replaceAll("[ ']","-") // turn spaces and quotes into hyphens
.replaceAll("[^0-9a-zA-Z-]",""); // remove everything not in our allowed char set
 
    
    - 2,314
- 2
- 23
- 17
These are commonly called "slugs" if you want to search for more information.
You may want to check out other answers such as How can I create a SEO friendly dash-delimited url from a string? and How to make Django slugify work properly with Unicode strings?
They cover C# and Python more than javascript but have some language-agnostic discussion about slug conventions and issues you may face when making them (such as uniqueness, unicode normalization problems, etc).
 
    
    - 1
- 1
 
    
    - 4,183
- 4
- 31
- 28
