Immagino di dover rimuovere i caratteri 0-31 e 127,
Esiste una funzione o un pezzo di codice per farlo in modo efficiente.
Immagino di dover rimuovere i caratteri 0-31 e 127,
Esiste una funzione o un pezzo di codice per farlo in modo efficiente.
Risposte:
Se il tuo Tardis è appena atterrato nel 1963 e vuoi solo i caratteri ASCII stampabili a 7 bit, puoi strappare tutto da 0-31 e 127-255 con questo:
$string = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $string);
Corrisponde a qualsiasi cosa nell'intervallo 0-31, 127-255 e lo rimuove.
Sei caduto in una macchina del tempo con vasca idromassaggio e sei tornato negli anni ottanta. Se hai una forma di ASCII a 8 bit, potresti voler mantenere i caratteri nell'intervallo 128-255. Una facile regolazione: basta cercare 0-31 e 127
$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);
Ah, bentornato al 21 ° secolo. Se si dispone di una stringa codificata UTF-8, è possibile utilizzare il /u
modificatore su regex
$string = preg_replace('/[\x00-\x1F\x7F]/u', '', $string);
Questo rimuove solo 0-31 e 127. Funziona in ASCII e UTF-8 perché entrambi condividono lo stesso intervallo di set di controllo (come notato da mgutt di seguito). A rigor di termini, questo avrebbe funzionato senza il /u
modificatore. Ma ti semplifica la vita se vuoi rimuovere altri caratteri ...
Se hai a che fare con Unicode, ci sono potenzialmente molti elementi non stampabili , ma consideriamo uno semplice: NO-BREAK SPACE (U + 00A0)
In una stringa UTF-8, questo sarebbe codificato come 0xC2A0
. Puoi cercare e rimuovere quella specifica sequenza, ma con il /u
modificatore in atto, puoi semplicemente aggiungere \xA0
alla classe di caratteri:
$string = preg_replace('/[\x00-\x1F\x7F\xA0]/u', '', $string);
preg_replace è piuttosto efficiente, ma se stai facendo questa operazione molto, potresti creare una matrice di caratteri che vuoi rimuovere e usare str_replace come indicato da mgutt di seguito, ad es.
//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, sembra che sarebbe veloce, ma non è sempre così, dovresti assolutamente fare un benchmark per vedere se ti salva qualcosa. Ho fatto alcuni benchmark su diverse lunghezze di stringa con dati casuali e questo schema è emerso 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
I tempi stessi sono per 10000 iterazioni, ma ciò che è più interessante sono le differenze relative. Fino a 512 caratteri, vedevo sempre vincere preg_replace. Nell'intervallo 1-8kb, str_replace ha un margine marginale.
Ho pensato che fosse un risultato interessante, quindi includilo qui. L'importante è non prendere questo risultato e usarlo per decidere quale metodo utilizzare, ma per confrontare i propri dati e quindi decidere.
Molte delle altre risposte qui non tengono conto dei caratteri unicode (ad es. Öäüßйȝîûηы ე மி ᚉ ⠛). In questo caso è possibile utilizzare quanto segue:
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $string);
C'è una strana classe di caratteri nell'intervallo \x80-\x9F
(appena sopra l'intervallo di caratteri ASCII a 7 bit) che sono tecnicamente i caratteri di controllo, ma nel tempo sono stati utilizzati in modo improprio per i caratteri stampabili. Se non hai problemi con questi, puoi usare:
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $string);
Se si desidera eliminare anche avanzamenti di riga, ritorni a capo, tabulazioni, spazi non interrotti e trattini morbidi, è possibile utilizzare:
$string = preg_replace('/[\x00-\x1F\x7F-\xA0\xAD]/u', '', $string);
Si noti che è necessario utilizzare virgolette singole per gli esempi sopra.
Se desideri rimuovere tutto tranne i caratteri ASCII stampabili di base (tutti i caratteri di esempio sopra verranno eliminati) puoi utilizzare:
$string = preg_replace( '/[^[:print:]]/', '',$string);
Per riferimento consultare http://www.fileformat.info/info/charset/UTF-8/list.htm
'/[\x00-\x1F\x80-\xC0]/u'
li lascia intatti; ma anche segno di divisione (F7) e moltiplicazione (D7).
\x7F-\x9F
?
A partire da PHP 5.2, abbiamo anche accesso a filter_var, di cui non ho visto alcuna menzione, quindi ho pensato di buttarlo lì. Per utilizzare filter_var per rimuovere i caratteri non stampabili <32 e> 127, è possibile eseguire:
Filtra i caratteri ASCII al di sotto di 32
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW);
Filtra i caratteri ASCII sopra 127
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_HIGH);
Striscia entrambi:
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH);
Puoi anche codificare html con caratteri bassi (newline, tab, ecc.) Mentre ti spogli in alto:
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_LOW|FILTER_FLAG_STRIP_HIGH);
Esistono anche opzioni per la rimozione di HTML, la disinfezione di e-mail e URL, ecc. Quindi, molte opzioni per la disinfezione (eliminazione dei dati) e persino la convalida (restituiscono false se non valide piuttosto che eliminazioni silenziose).
Sanificazione: http://php.net/manual/en/filter.filters.sanitize.php
Convalida: http://php.net/manual/en/filter.filters.validate.php
Tuttavia, c'è ancora il problema, che FILTER_FLAG_STRIP_LOW eliminerà i ritorni a capo e a capo, che per un'area di testo sono caratteri completamente validi ... quindi alcune delle risposte Regex, immagino, sono ancora necessarie a volte, ad esempio dopo aver esaminato questo thread, ho intenzione di farlo per textareas:
$string = preg_replace( '/[^[:print:]\r\n]/', '',$input);
Questo sembra più leggibile di un numero di regex che sono state eliminate dall'intervallo numerico.
puoi usare le classi di caratteri
/[[:cntrl:]]+/
questo è più semplice:
$ string = preg_replace ('/ [^ [: cntrl:]] /', '', $ string);
Tutte le soluzioni funzionano parzialmente, e anche sotto probabilmente non coprono tutti i casi. Il mio problema era nel tentativo di inserire una stringa in una tabella mysql utf8. La stringa (e i suoi byte) erano tutti conformi a utf8, ma presentavano diverse sequenze errate. Presumo che la maggior parte di essi fosse controllo o formattazione.
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;
}
Ad aggravare ulteriormente il problema è la tabella vs. server vs. connessione vs. rendering del contenuto, come abbiamo parlato un po 'qui
$s = preg_replace('/(\xF0\x9F[\x00-\xFF][\x00-\xFF])/', ' ', $s);
perché tutti i personaggi emoji stavano facendo casino mysql
La mia versione conforme UTF-8:
preg_replace('/[^\p{L}\s]/u','',$value);
Puoi usare un espresso normale per rimuovere tutto tranne i personaggi che desideri conservare:
$string=preg_replace('/[^A-Za-z0-9 _\-\+\&]/','',$string);
Sostituisce tutto ciò che non è (^) le lettere AZ o az, i numeri 0-9, lo spazio, il trattino basso, l'ipen, il segno più e la e commerciale - con nulla (cioè rimuovilo).
preg_replace('/(?!\n)[\p{Cc}]/', '', $response);
Ciò rimuoverà tutti i caratteri di controllo ( http://uk.php.net/manual/en/regexp.reference.unicode.php ) lasciando i \n
caratteri di nuova riga. Dalla mia esperienza, i caratteri di controllo sono quelli che più spesso causano i problemi di stampa.
/u
per i caratteri UTF-8. Potresti spiegare cosa fa la prima parte (?!\n)
?
Per eliminare tutti i caratteri non ASCII dalla stringa di input
$result = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $string);
Quel codice rimuove tutti i caratteri negli intervalli esadecimali 0-31 e 128-255, lasciando solo i caratteri esadecimali 32-127 nella stringa risultante, che chiamo $ risultato in questo esempio.
La risposta di @PaulDixon è completamente sbagliata , perché rimuove i caratteri ASCII estesi stampabili 128-255! è stato parzialmente corretto. Non so perché voglia ancora eliminare 128-255 da un set ASCII a 7 bit a 127 caratteri in quanto non ha i caratteri ASCII estesi.
Ma alla fine è stato importante non cancellare 128-255 perché ad esempio chr(128)
( \x80
) è il simbolo dell'euro in ASCII a 8 bit e molti caratteri UTF-8 in Windows mostrano un simbolo dell'euro e Android per quanto riguarda il mio test.
E ucciderà molti caratteri UTF-8 se rimuovete i caratteri ASCII 128-255 da una stringa UTF-8 (probabilmente i byte iniziali di un carattere UTF-8 multi-byte). Quindi non farlo! Sono caratteri completamente legali in tutti i file system attualmente utilizzati. L'unico intervallo riservato è 0-31 .
Invece usa questo per cancellare i caratteri non stampabili 0-31 e 127:
$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);
Si lavora in ASCII e UTF-8 perché entrambi condividono la stessa gamma di set di controlli .
L' alternativa più lenta più veloce¹ senza usare espressioni regolari:
$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 si desidera mantenere tutti i caratteri di spaziatura \t
, \n
e \r
, quindi rimuovere chr(9)
, chr(10)
e chr(13)
da questo elenco. Nota: il solito spazio bianco è chr(32)
quindi rimane nel risultato. Decidi te stesso se vuoi rimuovere lo spazio non interrotto chr(160)
in quanto può causare problemi.
¹ Testato da @PaulDixon e verificato da me stesso.
La risposta contrassegnata è perfetta ma manca il carattere 127 (DEL) che è anche un personaggio non stampabile
la mia risposta sarebbe
$string = preg_replace('/[\x00-\x1F\x7f-\xFF]/', '', $string);
"Cedivad" ha risolto il problema con il persistente risultato dei caratteri svedesi ÅÄÖ.
$text = preg_replace( '/[^\p{L}\s]/u', '', $text );
Grazie!
Per chiunque stia ancora cercando di farlo senza rimuovere i caratteri non stampabili, ma piuttosto sfuggendoli, l'ho fatto per dare una mano. Sentiti libero di migliorarlo! I caratteri vengono salvati in \\ x [A-F0-9] [A-F0-9].
Chiama così:
$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));
}
?>
Ho risolto il problema per UTF8 utilizzando https://github.com/neitanod/forceutf8
use ForceUTF8\Encoding;
$string = Encoding::fixUTF8($string);
La regex nella risposta selezionata non riesce per Unicode: 0x1d (con php 7.4)
una soluzione:
<?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;
da: UTF 8 String rimuove tutti i caratteri invisibili tranne newline