2010-06-23 21 views
6

Estoy tratando de extraer URL amigables para el SEO de cadenas que pueden contener caracteres especiales, letras con acentos, caracteres chinos similares, etc.
SO está haciendo esto y es la traducción de este título de la entrada enURL amigables para Java y SEO: © reate ╨ una URL http válida de una cadena compuesta por caracteres especiales

java-and-seo-friendly-urls-reate--a-valid-http-url-from-a-string-composed-by-s 

que estoy tratando de hacer esto en Java.
Estoy usando la solución this post con URLEncoder.encode para traducir el chino y otros símbolos a caracteres de URL válidos.

¿Alguna vez ha implementado algo como esto? ¿Hay una mejor manera?

+0

Esta pregunta tiene una forma basada en expresiones regulares para hacerlo en PHP: http://stackoverflow.com/questions/2580581/best-way-to-escape-and-create-a-slug –

Respuesta

1

No conozco ninguna forma estándar para esto, he estado utilizando una solución similair como lo que te refieres. No está seguro de cuál es mejor, así que aquí lo tienes:

public class TextUtils { 

private static final Pattern DIACRITICS_AND_FRIENDS = 
     Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+"); 

private static final Transliterator TO_LATIN_TRANSLITERATOR = Transliterator.getInstance("Any-Latin"); 

private static final Pattern EEQUIVALENTS = Pattern.compile("[ǝƏ]+"); 
private static final Pattern IEQUIVALENTS = Pattern.compile("[ı]+"); 
private static final Pattern DEQUIVALENTS = Pattern.compile("[Ððđ]+"); 
private static final Pattern OEQUIVALENTS = Pattern.compile("[Øø]+"); 
private static final Pattern LEQUIVALENTS = Pattern.compile("[Ł]+"); 

//all spaces, non-ascii and punctuation characters except _ and - 
private static final Pattern CRAP = Pattern.compile("[\\p{IsSpace}\\P{IsASCII}\\p{IsP}\\+&&[^_]]"); 
private static final Pattern SEPARATORS = Pattern.compile("[\\p{IsSpace}/`-]"); 

private static final Pattern URLFRIENDLY = Pattern.compile("([a-zA-Z0-9_])*"); 
private static final CharsetEncoder ASCII_ENCODER = Charset.forName("ISO-8859-1").newEncoder(); 

/** 
* Returns true when the input test contains only characters from the ASCII set, false otherwise. 
*/ 
public static boolean isPureAscii(String text) { 
    return ASCII_ENCODER.canEncode(text); 
} 

/** 
* Replaces all characters that normalize into two characters with their base symbol (e.g. ü -> u) 
*/ 
public static String replaceCombiningDiacriticalMarks(String text) { 
    return DIACRITICS_AND_FRIENDS.matcher(Normalizer.normalize(text, Normalizer.Form.NFKD)).replaceAll(""); 
} 

/** 
* Turns the input string into a url friendly variant (containing only alphanumeric characters and '-' and '_'). 
* If the input string cannot be converted an IllegalArgumentException is thrown. 
*/ 
public static String urlFriendlyStrict(String unfriendlyString) throws IllegalArgumentException { 
    String friendlyString = 
      urlFriendly(unfriendlyString); 

    //Assert can be removed to improve performance 
    Assert.isTrue(URLFRIENDLY.matcher(friendlyString).matches(), 
      format("Friendly string [%s] based on [%s] is not friendly enough", friendlyString, unfriendlyString)); 
    return friendlyString; 
} 

/** 
* Turns the input string into a url friendly variant (containing only alphanumeric characters and '-' and '_'). 
* Use {@link #urlFriendlyStrict(String)} to avoid potential bugs in this code. 
*/ 
private static String urlFriendly(String unfriendlyString) { 
    return removeCrappyCharacters(
      replaceEquivalentsOfSymbols(
        replaceCombiningDiacriticalMarks(
          transLiterateSymbols(
            replaceSeparatorsWithUnderscores(
              unfriendlyString.trim()))))).toLowerCase(); 
} 

private static String transLiterateSymbols(String incomprehensibleString) { 
    String latin = TO_LATIN_TRANSLITERATOR.transform(incomprehensibleString); 
    return latin; 
} 

private static String replaceEquivalentsOfSymbols(String unfriendlyString) { 
    return 
      LEQUIVALENTS.matcher(
        OEQUIVALENTS.matcher(
          DEQUIVALENTS.matcher(
            IEQUIVALENTS.matcher(
              EEQUIVALENTS.matcher(unfriendlyString).replaceAll("e")) 
              .replaceAll("i")) 
            .replaceAll("d")) 
          .replaceAll("o")) 
        .replaceAll("l"); 
} 

private static String removeCrappyCharacters(String unfriendlyString) { 
    return CRAP.matcher(unfriendlyString).replaceAll(""); 
} 

private static String replaceSeparatorsWithUnderscores(String unfriendlyString) { 
    return SEPARATORS.matcher(unfriendlyString).replaceAll("_"); 
} 

}

0

diría URLEncoder.encode es el camino a seguir. Se asignan todos los caracteres no URL y seguramente no desea reinventar la rueda (una y otra y otra vez).

+0

Sí, pero la codificación de caracteres es el último paso (después de limpiar acentos de cadena, etc.) para obtener una URL válida. Los caracteres codificados no son SEO amigables ... no funcionan bien en las búsquedas. – mickthompson

2

Esto podría ser un enfoque demasiado simplista al problema, pero podría usar expresiones regulares para eliminar todos los caracteres no estándar. Entonces, después de convertir su cadena a minúsculas, puede reemplazar todos los caracteres alfabéticos que no sean minúsculas con un carácter vacío y luego reemplazar todos los espacios con el carácter '-'.

private static String encodeForUrl(String input) { 
    return input.toLowerCase().replaceAll("[^a-z\\s]", "").replaceAll("\\s", "-"); 
} 
Cuestiones relacionadas