Me imagino que necesito eliminar los caracteres 0-31 y 127,
¿Existe una función o código para hacer esto de manera eficiente?
Me imagino que necesito eliminar los caracteres 0-31 y 127,
¿Existe una función o código para hacer esto de manera eficiente?
Respuestas:
Si su Tardis acaba de aterrizar en 1963, y solo desea los caracteres ASCII imprimibles de 7 bits, puede extraer todo de 0-31 y 127-255 con esto:
$string = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $string);
Coincide con cualquier cosa en el rango 0-31, 127-255 y lo elimina.
Te caíste en una máquina del tiempo del jacuzzi y volviste a los ochenta. Si tiene alguna forma de ASCII de 8 bits, entonces es posible que desee mantener los caracteres en el rango 128-255. Un ajuste fácil: solo busque 0-31 y 127
$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);
Ah, bienvenido de nuevo al siglo XXI. Si tiene una cadena codificada UTF-8, entonces el /u
modificador puede usarse en la expresión regular
$string = preg_replace('/[\x00-\x1F\x7F]/u', '', $string);
Esto simplemente elimina 0-31 y 127. Esto funciona en ASCII y UTF-8 porque ambos comparten el mismo rango de conjunto de control (como se indica en mgutt a continuación). Estrictamente hablando, esto funcionaría sin el /u
modificador. Pero hace la vida más fácil si quieres eliminar otros caracteres ...
Si se trata de Unicode, hay muchos elementos que no se pueden imprimir , pero consideremos uno simple: ESPACIO SIN INTERRUPCIONES (U + 00A0)
En una cadena UTF-8, esto se codificaría como 0xC2A0
. Puede buscar y eliminar esa secuencia específica, pero con el /u
modificador en su lugar, simplemente puede agregar \xA0
a la clase de caracteres:
$string = preg_replace('/[\x00-\x1F\x7F\xA0]/u', '', $string);
preg_replace es bastante eficiente, pero si está haciendo esta operación mucho, podría crear una serie de caracteres que desea eliminar y usar str_replace como se indica en mgutt a continuación, por ejemplo
//build an array we can re-use across several operations
$badchar=array(
// control characters
chr(0), chr(1), chr(2), chr(3), chr(4), chr(5), chr(6), chr(7), chr(8), chr(9), chr(10),
chr(11), chr(12), chr(13), chr(14), chr(15), chr(16), chr(17), chr(18), chr(19), chr(20),
chr(21), chr(22), chr(23), chr(24), chr(25), chr(26), chr(27), chr(28), chr(29), chr(30),
chr(31),
// non-printing characters
chr(127)
);
//replace the unwanted chars
$str2 = str_replace($badchar, '', $str);
Intuitivamente, esto parece que sería rápido, pero no siempre es el caso, definitivamente debes compararlo para ver si te ahorra algo. Hice algunos puntos de referencia en una variedad de longitudes de cadena con datos aleatorios, y este patrón surgió usando php 7.0.12
2 chars str_replace 5.3439ms preg_replace 2.9919ms preg_replace is 44.01% faster
4 chars str_replace 6.0701ms preg_replace 1.4119ms preg_replace is 76.74% faster
8 chars str_replace 5.8119ms preg_replace 2.0721ms preg_replace is 64.35% faster
16 chars str_replace 6.0401ms preg_replace 2.1980ms preg_replace is 63.61% faster
32 chars str_replace 6.0320ms preg_replace 2.6770ms preg_replace is 55.62% faster
64 chars str_replace 7.4198ms preg_replace 4.4160ms preg_replace is 40.48% faster
128 chars str_replace 12.7239ms preg_replace 7.5412ms preg_replace is 40.73% faster
256 chars str_replace 19.8820ms preg_replace 17.1330ms preg_replace is 13.83% faster
512 chars str_replace 34.3399ms preg_replace 34.0221ms preg_replace is 0.93% faster
1024 chars str_replace 57.1141ms preg_replace 67.0300ms str_replace is 14.79% faster
2048 chars str_replace 94.7111ms preg_replace 123.3189ms str_replace is 23.20% faster
4096 chars str_replace 227.7029ms preg_replace 258.3771ms str_replace is 11.87% faster
8192 chars str_replace 506.3410ms preg_replace 555.6269ms str_replace is 8.87% faster
16384 chars str_replace 1116.8811ms preg_replace 1098.0589ms preg_replace is 1.69% faster
32768 chars str_replace 2299.3128ms preg_replace 2222.8632ms preg_replace is 3.32% faster
Los tiempos en sí son para 10000 iteraciones, pero lo que es más interesante son las diferencias relativas. Hasta 512 caracteres, estaba viendo preg_replace ganar siempre. En el rango de 1-8kb, str_replace tenía un borde marginal.
Pensé que era un resultado interesante, así que incluirlo aquí. Lo importante no es tomar este resultado y usarlo para decidir qué método usar, sino compararlo con sus propios datos y luego decidir.
Muchas de las otras respuestas aquí no tienen en cuenta los caracteres unicode (por ejemplo, öäüßйȝîûηы ე மி ᚉ ⠛). En este caso puede usar lo siguiente:
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $string);
Hay una extraña clase de caracteres en el rango \x80-\x9F
(justo por encima del rango de caracteres ASCII de 7 bits) que técnicamente son caracteres de control, pero que con el tiempo se han utilizado incorrectamente para caracteres imprimibles. Si no tiene ningún problema con estos, puede usar:
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $string);
Si desea eliminar también los avances de línea, los retornos de carro, las pestañas, los espacios que no se rompen y los guiones suaves, puede usar:
$string = preg_replace('/[\x00-\x1F\x7F-\xA0\xAD]/u', '', $string);
Tenga en cuenta que debe usar comillas simples para los ejemplos anteriores.
Si desea despojar todo, excepto los caracteres ASCII imprimibles básicos (se eliminarán todos los caracteres de ejemplo anteriores), puede usar:
$string = preg_replace( '/[^[:print:]]/', '',$string);
Para referencia, consulte http://www.fileformat.info/info/charset/UTF-8/list.htm
'/[\x00-\x1F\x80-\xC0]/u'
los deja intactos; pero también el signo de división (F7) y multiplicación (D7).
\x7F-\x9F
?
Comenzando con PHP 5.2, también tenemos acceso a filter_var, del cual no he visto ninguna mención, así que pensé en lanzarlo allí. Para usar filter_var para quitar caracteres no imprimibles <32 y> 127, puede hacer lo siguiente:
Filtrar caracteres ASCII por debajo de 32
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW);
Filtrar caracteres ASCII por encima de 127
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_HIGH);
Tira ambos:
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH);
También puede codificar html con caracteres bajos (nueva línea, tabulación, etc.) mientras se despoja en alto:
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_LOW|FILTER_FLAG_STRIP_HIGH);
También hay opciones para eliminar HTML, desinfectar correos electrónicos y URL, etc. Por lo tanto, hay muchas opciones para desinfectar (eliminar datos) e incluso validar (devolver falso si no es válido en lugar de eliminar de forma silenciosa).
Desinfección: http://php.net/manual/en/filter.filters.sanitize.php
Validación: http://php.net/manual/en/filter.filters.validate.php
Sin embargo, todavía existe el problema, que FILTER_FLAG_STRIP_LOW eliminará los retornos de línea y carro, que para un área de texto son caracteres completamente válidos ... así que algunas de las respuestas de Regex, supongo, todavía son necesarias a veces, por ejemplo, después de revisar esto hilo, planeo hacer esto para textareas:
$string = preg_replace( '/[^[:print:]\r\n]/', '',$input);
Esto parece más legible que una serie de expresiones regulares que se eliminan por rango numérico.
puedes usar clases de personajes
/[[:cntrl:]]+/
esto es más simple:
$ string = preg_replace ('/ [^ [: cntrl:]] /', '', $ string);
Todas las soluciones funcionan parcialmente, e incluso a continuación probablemente no cubran todos los casos. Mi problema fue intentar insertar una cadena en una tabla utf8 mysql. La cadena (y sus bytes) se ajustaban a utf8, pero tenían varias secuencias malas. Supongo que la mayoría de ellos eran control o formateo.
function clean_string($string) {
$s = trim($string);
$s = iconv("UTF-8", "UTF-8//IGNORE", $s); // drop all non utf-8 characters
// this is some bad utf-8 byte sequence that makes mysql complain - control and formatting i think
$s = preg_replace('/(?>[\x00-\x1F]|\xC2[\x80-\x9F]|\xE2[\x80-\x8F]{2}|\xE2\x80[\xA4-\xA8]|\xE2\x81[\x9F-\xAF])/', ' ', $s);
$s = preg_replace('/\s+/', ' ', $s); // reduce all multiple whitespace to a single space
return $s;
}
Para exacerbar aún más el problema es la tabla vs. servidor vs. conexión vs. representación del contenido, como se mencionó un poco aquí.
$s = preg_replace('/(\xF0\x9F[\x00-\xFF][\x00-\xFF])/', ' ', $s);
porque todos los caracteres emoji estaban estropeando mysql
Mi versión compatible con UTF-8:
preg_replace('/[^\p{L}\s]/u','',$value);
Puede usar un expreso regular para eliminar todo, aparte de los caracteres que desea conservar:
$string=preg_replace('/[^A-Za-z0-9 _\-\+\&]/','',$string);
Reemplaza todo lo que no es (^) las letras AZ o az, los números 0-9, espacio, guión bajo, guión, más y ampersand, con nada (es decir, elimínelo).
preg_replace('/(?!\n)[\p{Cc}]/', '', $response);
Esto eliminará todos los caracteres de control ( http://uk.php.net/manual/en/regexp.reference.unicode.php ) dejando los \n
caracteres de nueva línea. Desde mi experiencia, los caracteres de control son los que con mayor frecuencia causan los problemas de impresión.
/u
para caracteres UTF-8. ¿Podría explicar qué hace la primera parte (?!\n)
?
Para quitar todos los caracteres no ASCII de la cadena de entrada
$result = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $string);
Ese código elimina cualquier carácter en los rangos hexadecimales 0-31 y 128-255, dejando solo los caracteres hexadecimales 32-127 en la cadena resultante, que llamo $ resultado en este ejemplo.
¡La respuesta de @PaulDixon es completamente incorrecta , ya que elimina los caracteres ASCII extendidos imprimibles 128-255! ha sido parcialmente corregido. No sé por qué todavía quiere eliminar 128-255 de un conjunto ASCII de 7 bits de 127 caracteres, ya que no tiene los caracteres ASCII extendidos.
Pero finalmente fue importante no eliminar 128-255 porque, por ejemplo, chr(128)
( \x80
) es el símbolo del euro en ASCII de 8 bits y muchas fuentes UTF-8 en Windows muestran un símbolo del euro y Android con respecto a mi propia prueba.
Y eliminará muchos caracteres UTF-8 si elimina los caracteres ASCII 128-255 de una cadena UTF-8 (probablemente los bytes iniciales de un carácter UTF-8 de varios bytes). ¡Entonces no hagas eso! Son caracteres completamente legales en todos los sistemas de archivos utilizados actualmente. El único rango reservado es 0-31 .
En su lugar, use esto para eliminar los caracteres no imprimibles 0-31 y 127:
$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);
Se trabaja en ASCII y UTF-8 , porque ambas comparten el mismo rango de ajuste de control .
La alternativa más rápida y lenta¹ sin usar expresiones regulares:
$string = str_replace(array(
// control characters
chr(0), chr(1), chr(2), chr(3), chr(4), chr(5), chr(6), chr(7), chr(8), chr(9), chr(10),
chr(11), chr(12), chr(13), chr(14), chr(15), chr(16), chr(17), chr(18), chr(19), chr(20),
chr(21), chr(22), chr(23), chr(24), chr(25), chr(26), chr(27), chr(28), chr(29), chr(30),
chr(31),
// non-printing characters
chr(127)
), '', $string);
Si desea mantener todos los espacios en blanco \t
, \n
y \r
, a continuación, quitar chr(9)
, chr(10)
y chr(13)
de esta lista. Nota: El espacio en blanco habitual es chr(32)
para que permanezca en el resultado. Decide si quieres eliminar el espacio chr(160)
que no se rompe, ya que puede causar problemas.
¹ Probado por @PaulDixon y verificado por mí mismo.
La respuesta marcada es perfecta pero pierde el carácter 127 (DEL), que también es un carácter no imprimible
mi respuesta seria
$string = preg_replace('/[\x00-\x1F\x7f-\xFF]/', '', $string);
"cedivad" me resolvió el problema con el resultado persistente de los caracteres suecos ÅÄÖ.
$text = preg_replace( '/[^\p{L}\s]/u', '', $text );
¡Gracias!
Para cualquiera que todavía esté buscando cómo hacer esto sin eliminar los caracteres no imprimibles, sino escapar de ellos, hice esto para ayudar. ¡Siéntete libre de mejorarlo! Los caracteres se escapan a \\ x [A-F0-9] [A-F0-9].
Llame así:
$escaped = EscapeNonASCII($string);
$unescaped = UnescapeNonASCII($string);
<?php
function EscapeNonASCII($string) //Convert string to hex, replace non-printable chars with escaped hex
{
$hexbytes = strtoupper(bin2hex($string));
$i = 0;
while ($i < strlen($hexbytes))
{
$hexpair = substr($hexbytes, $i, 2);
$decimal = hexdec($hexpair);
if ($decimal < 32 || $decimal > 126)
{
$top = substr($hexbytes, 0, $i);
$escaped = EscapeHex($hexpair);
$bottom = substr($hexbytes, $i + 2);
$hexbytes = $top . $escaped . $bottom;
$i += 8;
}
$i += 2;
}
$string = hex2bin($hexbytes);
return $string;
}
function EscapeHex($string) //Helper function for EscapeNonASCII()
{
$x = "5C5C78"; //\x
$topnibble = bin2hex($string[0]); //Convert top nibble to hex
$bottomnibble = bin2hex($string[1]); //Convert bottom nibble to hex
$escaped = $x . $topnibble . $bottomnibble; //Concatenate escape sequence "\x" with top and bottom nibble
return $escaped;
}
function UnescapeNonASCII($string) //Convert string to hex, replace escaped hex with actual hex.
{
$stringtohex = bin2hex($string);
$stringtohex = preg_replace_callback('/5c5c78([a-fA-F0-9]{4})/', function ($m) {
return hex2bin($m[1]);
}, $stringtohex);
return hex2bin(strtoupper($stringtohex));
}
?>
Resolví el problema para UTF8 usando https://github.com/neitanod/forceutf8
use ForceUTF8\Encoding;
$string = Encoding::fixUTF8($string);
La expresión regular en la respuesta seleccionada falla para Unicode: 0x1d (con php 7.4)
una solución:
<?php
$ct = 'différents'."\r\n test";
// fail for Unicode: 0x1d
$ct = preg_replace('/[\x00-\x1F\x7F]$/u', '',$ct);
// work for Unicode: 0x1d
$ct = preg_replace( '/[^\P{C}]+/u', "", $ct);
// work for Unicode: 0x1d and allow line break
$ct = preg_replace( '/[^\P{C}\n]+/u', "", $ct);
echo $ct;
from: UTF 8 String elimina todos los caracteres invisibles excepto la nueva línea