2010-10-24 18 views
5

marcos web como Rails y Django ha incorporado soporte para "babosas", que se utilizan para generar URL legibles y SEO-amigable:¿Cómo puedo generar slugs URL en Perl?

Una cadena babosa normalmente contiene solo los caracteres a-z, 0-9 y - y, por lo tanto, puede escribirse sin escape de URL (piense en "foo% 20bar").

Busco una función babosa Perl que dado cualquier cadena Unicode válida devolverá una representación babosa (a-z, 0-9 y -).

Una función babosa muy trivial sería algo a lo largo de las líneas de:

$input = lc($input), 
$input =~ s/[^a-z0-9-]//g; 

Sin embargo, esta implementación no se ocuparía de la internacionalización y acentos (Quiero ë para convertirse en e). Una forma de evitar esto sería enumerar todos los casos especiales, pero eso no sería muy elegante. Estoy buscando algo más bien pensado y general.

Mi pregunta:

  • Cuál es la forma más general/práctico para generar babosas tipo Django/Rails en Perl?This es cómo resolví el mismo problema en Java.
+0

Hazlo de la misma manera que lo hiciste en Java. ¿Hay alguna operación en particular que no sepa cómo traducir? –

+0

brian: Sí, la operación que no sabía cómo traducir era "String normalized = Normalizer.normalize (nowhitespace, Form.NFD);". Unicode :: Normalize lo resolvió. Vea la respuesta de Cameron. – knorv

Respuesta

11

El slugify filter utilizado actualmente en Django se traduce (más o menos) para el siguiente código Perl:

use Unicode::Normalize; 

sub slugify($) { 
    my ($input) = @_; 

    $input = NFKD($input);   # Normalize (decompose) the Unicode string 
    $input =~ tr/\000-\177//cd; # Strip non-ASCII characters (>127) 
    $input =~ s/[^\w\s-]//g;  # Remove all characters that are not word characters (includes _), spaces, or hyphens 
    $input =~ s/^\s+|\s+$//g;  # Trim whitespace from both ends 
    $input = lc($input); 
    $input =~ s/[-\s]+/-/g;  # Replace all occurrences of spaces and hyphens with a single hyphen 

    return $input; 
} 

Dado que también quiere cambiar los caracteres acentuados a los acentuadas, lanzando en una llamada a unidecode (definido en Text::Unidecode) antes de eliminar los caracteres que no son ASCII parece ser su mejor opción (as pointed out by phaylon).

En ese caso, la función podría ser:

use Unicode::Normalize; 
use Text::Unidecode; 

sub slugify_unidecode($) { 
    my ($input) = @_; 

    $input = NFC($input);   # Normalize (recompose) the Unicode string 
    $input = unidecode($input); # Convert non-ASCII characters to closest equivalents 
    $input =~ s/[^\w\s-]//g;  # Remove all characters that are not word characters (includes _), spaces, or hyphens 
    $input =~ s/^\s+|\s+$//g;  # Trim whitespace from both ends 
    $input = lc($input); 
    $input =~ s/[-\s]+/-/g;  # Replace all occurrences of spaces and hyphens with a single hyphen 

    return $input; 
} 

El primero funciona bien para las cadenas que son principalmente ASCII, pero se queda corto cuando se forma toda la cadena de caracteres no ASCII, ya que todos ellos ser despojado, dejándote con una cuerda vacía.

Salida de ejemplo:

string  | slugify  | slugify_unidecode 
------------------------------------------------- 
hello world  hello world  hello world 
北亰       bei-jing 
liberté   liberta   liberte 

Nota cómo 北 亰 consigue slugifies para nada con la implementación de inspiración Django. Tenga en cuenta también la diferencia que hace la normalización de NFC: liberté se convierte en 'liberta' con NFKD después de eliminar la segunda parte del carácter descompuesto, pero se convierte en 'libert' después de eliminar la 'é' reensamblada con NFC.

3

String::Dirify se utiliza para crear babosas en el software de blog Movable Type/Melody.

+0

¿Eso hace unicode o simplemente ISO-8859? – MkV

+0

Los puntos de código más allá de 255 no se tocan. – daxim

+0

Probado con algunos chinos, parece lo que necesito. – Weiyan

0

La solución más llave en mano es utilizar Text::Slugify que hace lo que necesita. Es una cantidad trivial de código que proporciona muy bien una función slugify para usted.

Se basa en Text::Unaccent::PurePerl para eliminar los acentos de los caracteres.

Cuestiones relacionadas