Eu imagino que preciso remover os caracteres 0-31 e 127,
Existe uma função ou parte do código para fazer isso com eficiência.
Eu imagino que preciso remover os caracteres 0-31 e 127,
Existe uma função ou parte do código para fazer isso com eficiência.
Respostas:
Se a sua Tardis acabou de chegar em 1963 e você deseja apenas os caracteres ASCII imprimíveis de 7 bits, pode extrair tudo de 0 a 31 e 127 a 255 com isso:
$string = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $string);
Corresponde a qualquer coisa no intervalo de 0 a 31, 127 a 255 e o remove.
Você caiu em uma máquina do tempo de banheira de hidromassagem e voltou aos anos oitenta. Se você possui algum tipo de ASCII de 8 bits, convém manter os caracteres no intervalo 128-255. Um ajuste fácil - basta procurar 0-31 e 127
$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);
Bem-vindo de volta ao século XXI. Se você tiver uma string codificada em UTF-8, o /u
modificador poderá ser usado na regex
$string = preg_replace('/[\x00-\x1F\x7F]/u', '', $string);
Isso apenas remove 0-31 e 127. Isso funciona em ASCII e UTF-8 porque ambos compartilham o mesmo intervalo de conjunto de controle (conforme observado por mgutt abaixo). A rigor, isso funcionaria sem o /u
modificador. Mas facilita a vida se você deseja remover outros caracteres ...
Se você estiver lidando com Unicode, há potencialmente muitos elementos que não são de impressão , mas vamos considerar um simples: NO-BREAK SPACE (U + 00A0)
Em uma sequência UTF-8, isso seria codificado como 0xC2A0
. Você pode procurar e remover essa sequência específica, mas com o /u
modificador instalado, você pode simplesmente adicionar \xA0
à classe de caracteres:
$string = preg_replace('/[\x00-\x1F\x7F\xA0]/u', '', $string);
preg_replace é bastante eficiente, mas se você estiver fazendo muito esta operação, poderá criar uma matriz de caracteres que deseja remover e usar str_replace conforme observado por mgutt abaixo, por exemplo
//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, parece que seria rápido, mas nem sempre é o caso; você deve definitivamente fazer um benchmark para ver se isso poupa alguma coisa. Eu fiz alguns benchmarks em vários comprimentos de string com dados aleatórios, e esse padrão surgiu usando o 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
Os horários são para 10000 iterações, mas o mais interessante são as diferenças relativas. Até 512 caracteres, eu estava vendo preg_replace sempre ganhar. No intervalo de 1-8kb, str_replace tinha uma margem marginal.
Eu pensei que era um resultado interessante, então incluí-lo aqui. O importante não é pegar esse resultado e usá-lo para decidir qual método usar, mas para comparar seus próprios dados e depois decidir.
Muitas das outras respostas aqui não levam em consideração caracteres unicode (por exemplo, öäüßйȝîûηы ე மி ᚉ ⠛). Nesse caso, você pode usar o seguinte:
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $string);
Há uma classe estranha de caracteres no intervalo \x80-\x9F
(logo acima do intervalo ASCII de 7 bits) que são tecnicamente caracteres de controle, mas com o tempo foram utilizados incorretamente para caracteres imprimíveis. Se você não tiver nenhum problema com isso, poderá usar:
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $string);
Se você também deseja remover faixas de alimentação de linha, retornos de carro, guias, espaços sem quebra e hífens suaves, você pode usar:
$string = preg_replace('/[\x00-\x1F\x7F-\xA0\xAD]/u', '', $string);
Observe que você deve usar aspas simples para os exemplos acima.
Se você deseja remover tudo, exceto caracteres ASCII básicos imprimíveis (todos os caracteres de exemplo acima serão removidos), você pode usar:
$string = preg_replace( '/[^[:print:]]/', '',$string);
Para referência, consulte http://www.fileformat.info/info/charset/UTF-8/list.htm
'/[\x00-\x1F\x80-\xC0]/u'
os deixa intactos; mas também sinal de divisão (F7) e multiplicação (D7).
\x7F-\x9F
?
A partir do PHP 5.2, também temos acesso ao filter_var, que eu não vi nenhuma menção, então pensei em lançá-lo lá fora. Para usar filter_var para remover caracteres não imprimíveis <32 e> 127, você pode:
Filtrar caracteres ASCII abaixo de 32
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW);
Filtrar caracteres ASCII acima de 127
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_HIGH);
Retire ambos:
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH);
Você também pode codificar caracteres baixos em html (nova linha, guia etc.) enquanto retira o conteúdo alto:
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_LOW|FILTER_FLAG_STRIP_HIGH);
Também existem opções para remover HTML, higienizar e-mails e URLs, etc. Portanto, muitas opções para higienização (remover dados) e até validação (retornam false se não for válido em vez de remover silenciosamente).
Sanitização: http://php.net/manual/en/filter.filters.sanitize.php
Validação: http://php.net/manual/en/filter.filters.validate.php
No entanto, ainda existe o problema, que o FILTER_FLAG_STRIP_LOW retira novas linhas e retornos de carro, que para uma área de texto são caracteres completamente válidos ... portanto, algumas respostas do Regex, eu acho, ainda são necessárias às vezes, por exemplo, depois de revisar isso thread, pretendo fazer isso para textareas:
$string = preg_replace( '/[^[:print:]\r\n]/', '',$input);
Isso parece mais legível do que um número de expressões regulares removidas por intervalo numérico.
você pode usar classes de caracteres
/[[:cntrl:]]+/
isso é mais simples:
$ string = preg_replace ('/ [^ [: cntrl:]] /', '', $ string);
Todas as soluções funcionam parcialmente, e mesmo abaixo provavelmente não cobre todos os casos. Meu problema foi ao tentar inserir uma string em uma tabela mysql utf8. A string (e seus bytes) todos estavam em conformidade com utf8, mas tinham várias seqüências incorretas. Presumo que a maioria deles tenha controle ou formatação.
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 agravar ainda mais o problema é a tabela x servidor x conexão x renderização do conteúdo, como discutido aqui um pouco
$s = preg_replace('/(\xF0\x9F[\x00-\xFF][\x00-\xFF])/', ' ', $s);
causa de todos os caracteres emoji estavam atrapalhando mysql
Minha versão compatível com UTF-8:
preg_replace('/[^\p{L}\s]/u','',$value);
Você pode usar um expresso regular para remover tudo, exceto os caracteres que deseja manter:
$string=preg_replace('/[^A-Za-z0-9 _\-\+\&]/','',$string);
Substitui tudo o que não é (^) as letras AZ ou az, os números de 0 a 9, espaço, sublinhado, hífen, mais e comercial - por nada (por exemplo, remova-o).
preg_replace('/(?!\n)[\p{Cc}]/', '', $response);
Isso removerá todos os caracteres de controle ( http://uk.php.net/manual/en/regexp.reference.unicode.php ) deixando os \n
caracteres de nova linha. Pela minha experiência, os caracteres de controle são os que mais frequentemente causam problemas de impressão.
/u
para caracteres UTF-8. Você poderia explicar o que a primeira parte (?!\n)
faz?
Para retirar todos os caracteres não ASCII da sequência de entrada
$result = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $string);
Esse código remove qualquer caractere nos intervalos hexadecimais 0-31 e 128-255, deixando apenas os caracteres hexadecimais 32-127 na cadeia resultante, que eu chamo de $ result neste exemplo.
A resposta de @PaulDixon está completamente errada , porque remove os caracteres ASCII estendidos imprimíveis 128-255! foi parcialmente corrigido. Não sei por que ele ainda deseja excluir 128-255 de um conjunto ASCII de 7 bits e 127 caracteres, pois não possui os caracteres ASCII estendidos.
Mas, finalmente, era importante não excluir 128-255 porque, por exemplo chr(128)
( \x80
), o sinal de euro é ASCII de 8 bits e muitas fontes UTF-8 no Windows exibem um sinal de euro e o Android em relação ao meu próprio teste.
E ele matará muitos caracteres UTF-8 se você remover os caracteres ASCII 128-255 de uma string UTF-8 (provavelmente os bytes iniciais de um caractere UTF-8 de vários bytes). Então não faça isso! Eles são caracteres completamente legais em todos os sistemas de arquivos usados atualmente. O único intervalo reservado é de 0 a 31 .
Em vez disso, use isso para excluir os caracteres não imprimíveis 0-31 e 127:
$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);
Ele funciona em ASCII e UTF-8 porque ambos compartilham o mesmo intervalo de conjunto de controle .
A alternativa mais lenta¹ mais rápida sem usar expressões 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);
Se você quiser manter todos os espaços em branco \t
, \n
e \r
, em seguida, remover chr(9)
, chr(10)
e chr(13)
a partir dessa lista. Nota: O espaço em branco usual é chr(32)
para que permaneça no resultado. Decida-se se você deseja remover o espaço sem quebra, chr(160)
pois isso pode causar problemas.
¹ Testado por @PaulDixon e verificado por mim mesmo.
O anwser marcado é perfeito, mas perde o caractere 127 (DEL), que também é um caractere não imprimível
minha resposta seria
$string = preg_replace('/[\x00-\x1F\x7f-\xFF]/', '', $string);
"cedivad" resolveu o problema para mim com resultado persistente dos caracteres suecos ÅÄÖ.
$text = preg_replace( '/[^\p{L}\s]/u', '', $text );
Obrigado!
Para quem ainda está procurando como fazer isso sem remover os caracteres não imprimíveis, mas escapando deles, fiz isso para ajudar. Sinta-se livre para melhorá-lo! Os caracteres são escapados para \\ x [A-F0-9] [A-F0-9].
Ligue assim:
$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));
}
?>
Resolvi o problema para o UTF8 usando https://github.com/neitanod/forceutf8
use ForceUTF8\Encoding;
$string = Encoding::fixUTF8($string);
O regex na resposta selecionada falha para Unicode: 0x1d (com php 7.4)
uma solução:
<?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 remove todos os caracteres invisíveis, exceto a nova linha