Reemplace todos los caracteres que no sean letras y números con un guión [duplicate]

7 minutos de lectura

avatar de usuario de user115422
usuario115422

Estoy enfrentando un problema con las URL, quiero poder convertir títulos que puedan contener cualquier cosa y despojarlos de todos los caracteres especiales para que solo tengan letras y números y, por supuesto, me gustaría reemplazar los espacios con guiones.

¿Cómo se haría esto? He oído mucho sobre el uso de expresiones regulares (regex)…

Avatar de usuario de Terry Harvey
terry harvey

Esto debería hacer lo que estás buscando:

function clean($string) {
   $string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.

   return preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.
}

Uso:

echo clean('a|"bc!@£de^&$f g');

Saldrá: abcdef-g

Editar:

Oye, solo una pregunta rápida, ¿cómo puedo evitar que varios guiones estén uno al lado del otro? y hacer que los reemplacen con solo 1?

function clean($string) {
   $string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.
   $string = preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.

   return preg_replace('/-+/', '-', $string); // Replaces multiple hyphens with single one.
}

  • @all Tenga en cuenta que esto no funcionará con UTF-8

    – yang

    1 de enero de 2013 a las 22:11

  • @metal_fan, ¿qué significaría eso… quiero decir, qué tan malo puede ser?

    – usuario115422

    1 de enero de 2013 a las 22:15


  • La primera línea debe tener un espacio como primer parámetro. En este momento es solo una cadena vacía. Corregido aquí: $cadena = str_replace(‘ ‘, ‘-‘, $cadena);

    –Russell Strauss

    24 de julio de 2013 a las 17:34

  • @TerryHarvey, esto no funcionaría si ‘es el último carácter, por ejemplo, América’ es la palabra clave que obtiene y necesita limpiarlo.

    – requerir una vez

    22 de octubre de 2013 a las 15:08

  • ¿Hay alguna buena razón por la que la función de limpieza hace un str_replace antes de preg_replace ya que reg_replace también se ocupa de los espacios en blanco?

    – País de las maravillas duro

    20/10/2014 a las 19:56

Avatar de usuario de LSerni
LSerni

limpieza mejorada

La siguiente solución tiene una versión “SEO más amigable”:

function hyphenize($string) {
    $dict = array(
        "I'm"      => "I am",
        "thier"    => "their",
        // Add your own replacements here
    );
    return strtolower(
        preg_replace(
          array( '#[\\s-]+#', '#[^A-Za-z0-9. -]+#' ),
          array( '-', '' ),
          // the full cleanString() can be downloaded from http://www.unexpectedit.com/php/php-clean-string-of-utf8-chars-convert-to-similar-ascii-char
          cleanString(
              str_replace( // preg_replace can be used to support more complicated replacements
                  array_keys($dict),
                  array_values($dict),
                  urldecode($string)
              )
          )
        )
    );
}

function cleanString($text) {
    $utf8 = array(
        '/[áàâãªä]/u'   =>   'a',
        '/[ÁÀÂÃÄ]/u'    =>   'A',
        '/[ÍÌÎÏ]/u'     =>   'I',
        '/[íìîï]/u'     =>   'i',
        '/[éèêë]/u'     =>   'e',
        '/[ÉÈÊË]/u'     =>   'E',
        '/[óòôõºö]/u'   =>   'o',
        '/[ÓÒÔÕÖ]/u'    =>   'O',
        '/[úùûü]/u'     =>   'u',
        '/[ÚÙÛÜ]/u'     =>   'U',
        '/ç/'           =>   'c',
        '/Ç/'           =>   'C',
        '/ñ/'           =>   'n',
        '/Ñ/'           =>   'N',
        '/–/'           =>   '-', // UTF-8 hyphen to "normal" hyphen
        '/[’‘‹›‚]/u'    =>   ' ', // Literally a single quote
        '/[“”«»„]/u'    =>   ' ', // Double quote
        '/ /'           =>   ' ', // nonbreaking space (equiv. to 0x160)
    );
    return preg_replace(array_keys($utf8), array_values($utf8), $text);
}

La justificación de las funciones anteriores (que encuentro forma ineficiente – el de abajo es mejor) es que un servicio que no será nombrado aparentemente corrió revisiones ortográficas y reconocimiento de palabras clave en las URL.

Después de perder mucho tiempo con las paranoias de un cliente, descubrí que eran no imaginando cosas después de todo: sus expertos en SEO [I am definitely not one] informó que, digamos, convertir “Viaggi Economy Perù” a viaggi-economy-peru “se portó mejor” que viaggi-economy-per (la “limpieza” anterior eliminó los caracteres UTF8; Bogotá convertirse bogotá, Medellín convertirse Medellín etcétera).

También hubo algunas faltas de ortografía comunes que parecían influir en los resultados, y la única explicación que tenía sentido para mí es que nuestra URL estaba siendo desempaquetada, las palabras destacadas y utilizadas para impulsar Dios sabe qué algoritmos de clasificación. Y esos algoritmos aparentemente habían sido alimentados con cadenas limpiadas con UTF8, por lo que “Perù” se convirtió en “Peru” en lugar de “Per”. “Per” no coincidía y lo recibió en el cuello.

Para mantener los caracteres UTF8 y reemplazar algunos errores ortográficos, la función más rápida a continuación se convirtió en la función más precisa (?) de arriba. $dict necesita ser hecho a mano, por supuesto.

Respuesta anterior

Un enfoque simple:

// Remove all characters except A-Z, a-z, 0-9, dots, hyphens and spaces
// Note that the hyphen must go last not to be confused with a range (A-Z)
// and the dot, NOT being special (I know. My life was a lie), is NOT escaped

$str = preg_replace('/[^A-Za-z0-9. -]/', '', $str);

// Replace sequences of spaces with hyphen
$str = preg_replace('/  */', '-', $str);

// The above means "a space, followed by a space repeated zero or more times"
// (should be equivalent to / +/)

// You may also want to try this alternative:
$str = preg_replace('/\\s+/', '-', $str);

// where \s+ means "zero or more whitespaces" (a space is not necessarily the
// same as a whitespace) just to be sure and include everything

Tenga en cuenta que es posible que primero tenga que urldecode() la URL, ya que %20 y + son en realidad espacios; es decir, si tiene “Never%20gonna%20give%20you%20up”, quiere que se convierta en Never-gonna- give-you-up, no Never20gonna20dar20you20up . Puede que no lo necesites, pero pensé en mencionar la posibilidad.

Entonces, la función terminada junto con los casos de prueba:

function hyphenize($string) {
    return 
    ## strtolower(
          preg_replace(
            array('#[\\s-]+#', '#[^A-Za-z0-9. -]+#'),
            array('-', ''),
        ##     cleanString(
              urldecode($string)
        ##     )
        )
    ## )
    ;
}

print implode("\n", array_map(
    function($s) {
            return $s . ' becomes ' . hyphenize($s);
    },
    array(
    'Never%20gonna%20give%20you%20up',
    "I'm not the man I was",
    "'Légeresse', dit sa majesté",
    )));


Never%20gonna%20give%20you%20up    becomes  never-gonna-give-you-up
I'm not the man I was              becomes  im-not-the-man-I-was
'Légeresse', dit sa majesté        becomes  legeresse-dit-sa-majeste

Para manejar UTF-8 utilicé un cleanString implementación encontrada en línea (enlace roto desde entonces, pero una copia simplificada con todos los caracteres UTF8 no demasiado esotéricos se encuentra al comienzo de la respuesta; también es fácil agregarle más caracteres si es necesario) que convierte los caracteres UTF8 a normal caracteres, preservando así la palabra “mirar” tanto como sea posible. Podría simplificarse y envolverse dentro de la función aquí para el rendimiento.

La función anterior también implementa la conversión a minúsculas, pero eso es un gusto. El código para hacerlo ha sido comentado.

  • Gran solución, gracias. Sin embargo, un ajuste, cambie la segunda matriz en hypenize preg_replace para evitar que la palabra 1 y la palabra 2 se conviertan en palabra 1–palabra 2, matriz (”, ‘-‘),

    – Solvisión

    7 ago 2022 a las 20:01

  • strtr() es más adecuado para consumir su asociativo $dict formación. array_values() no es necesario cuando se alimenta $dict a str_replace(). ¿Por qué hay un espacio en la lista de la clase de caracteres negados si la existencia de un espacio es imposible debido al patrón ejecutado anteriormente con \s? ('#[^A-Za-z0-9. -]+#') ¿Por qué no disfrutar de un patrón más pequeño usando el modificador de patrón que no distingue entre mayúsculas y minúsculas? i?

    – mickmackusa

    15 de agosto de 2022 a las 5:18


Aquí, echa un vistazo a esta función:

function seo_friendly_url($string){
    $string = str_replace(array('[\', \']'), '', $string);
    $string = preg_replace('/\[.*\]/U', '', $string);
    $string = preg_replace('/&(amp;)?#?[a-z0-9]+;/i', '-', $string);
    $string = htmlentities($string, ENT_COMPAT, 'utf-8');
    $string = preg_replace('/&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig|quot|rsquo);/i', '\\1', $string );
    $string = preg_replace(array('/[^a-z0-9]/i', '/[-]+/') , '-', $string);
    return strtolower(trim($string, '-'));
}

  • Un guión literal no se beneficia de estar encuadrado dentro de llaves cuadradas. -+ significa lo mismo que tu [-]+. A esta respuesta le falta su explicación educativa. ¿Por qué estás haciendo cada uno de estos pasos? ¿Como funciona? ¿Por qué otros desarrolladores deberían copiar esto en su proyecto? Si va a convertir incondicionalmente la cadena resultante a minúsculas, ¿por qué no simplificar todos los procesos anteriores llamando strtolower() cuando la cadena se recibe por primera vez? El espalda con espalda preg_replace() las llamadas se pueden consolidar porque la función puede tomar matrices de búsquedas y reemplazos.

    – mickmackusa

    15 de agosto de 2022 a las 5:26


¿Ha sido útil esta solución?