Java-код/​​библиотека для создания пули (для использования в симпатичных URL-адресах)

Веб-фреймворки, такие как Rails и Django, имеют встроенную поддержку "slugs", которые используются для создания читаемых и SEO-дружественных URL-адресов:

Строка slug обычно содержит только символы a-z, 0-9 и - и поэтому может быть написана без экранирования URL (подумайте "foo %20bar" ).

Я ищу функцию Java slug, которая с учетом любой допустимой строки Unicode вернет представление slug (a-z, 0-9 и -).

Тривиальной функцией slug будет что-то вроде строк:

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

Однако эта реализация не будет обрабатывать интернационализацию и акценты (ë > e). Одним из способов этого было бы перечисление всех особых случаев, но это было бы не очень элегантно. Я ищу что-то более продуманное и общее.

Мой вопрос:

  • Каков наиболее общий/практичный способ создания пулов Django/Rails в Java?

Ответ 1

Нормализовать вашу строку, используя каноническое разложение:

  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 (& # xDF; - используется на немецком языке) или любого нелатинского алфавита (греческий, кириллический, CJK и т.д.).

Be careful when changing the case of a string. Upper and lower case forms are dependent on alphabets. In Turkish, the capitalization of U+0069 (i) is U+0130 (İ), not U+0049 (I) so you risk introducing a non-latin1 character back into your string if you use String.toLowerCase() under a Turkish locale.

Ответ 4

Я расширил ответ @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("^-|-$","");
  }

Ответ 5

Предложение 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);
}