PHP: comment supprimer tous les caractères non imprimables dans une chaîne de caractères?

j'imagine que j'ai besoin de supprimer des caractères de 0 à 31 et 127,

Est-il une fonction ou un morceau de code pour le faire efficacement.

133
demandé sur Stewart Robinson 2009-07-24 14:48:16

16 réponses

7 bit ASCII?

si votre Tardis vient d'atterrir en 1963, et que vous voulez juste les 7 caractères ASCII imprimables, vous pouvez tout arracher de 0-31 et 127-255 avec ceci:

$string = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $string);

il correspond à tout dans la gamme 0-31, 127-255 et le supprime.

8 bits ASCII étendu?

vous êtes tombé dans une machine à remonter le temps, et vous êtes de retour dans les années 80. Si vous avez une forme de 8 bits ASCII, alors vous pourriez vouloir garder les chars dans la portée 128-255. Un ajustement facile-il suffit de regarder pour 0-31 et 127

$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);

UTF-8?

Ah, bienvenue au 21ème siècle. Si vous avez une chaîne encodée UTF-8, alors le /u modificateur peut être utilisé sur le regex

$string = preg_replace('/[\x00-\x1F\x7F]/u', '', $string);

cela supprime juste 0-31 et 127. Cela fonctionne en ASCII et UTF-8 parce que les deux partagent le même plage de réglage de contrôle (tel que noté par mgutt ci-dessous). À proprement parler, cela fonctionnerait sans le modificateur /u . Mais cela rend la vie plus facile si vous voulez enlever d'autres chars...

si vous avez affaire à Unicode, il ya potentiellement beaucoup d'éléments non-impression , mais considérons un simple: espace sans rupture (U+00A0) "1519250920

dans une chaîne UTF-8, ceci serait encodé comme 0xC2A0 . Vous pouvez rechercher et supprimer cette séquence spécifique, mais avec le /u modificateur en place, vous pouvez simplement ajouter \xA0 à la classe de caractères:

$string = preg_replace('/[\x00-\x1F\x7F\xA0]/u', '', $string);

Addendum: Qu'en est-il de str_replace?

preg_replace est assez efficace, mais si vous faites cette opération beaucoup, vous pouvez construire un tableau de caractères que vous voulez supprimer, et utiliser str_replace comme noté par mgutt ci-dessous, par exemple

//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);

intuitivement, il semble que ce serait rapide, mais ce n'est pas toujours le cas, vous devriez certainement benchmark pour voir si elle vous sauve quelque chose. J'ai fait quelques repères à travers une variété de longueurs de chaîne avec des données aléatoires, et ce modèle a émergé en utilisant 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

les timings eux-mêmes sont pour 10000 itérations, mais ce qui est plus intéressant est les différences relatives. Jusqu'à 512 chars, je voyais preg_replace toujours gagner. Dans le 1-8 ko gamme, str_replace avait un avantage marginal.

j'ai pensé que c'était un résultat intéressant, donc l'inclure ici. l'important n'est pas de prendre ce résultat et de l'utiliser pour décider quelle méthode à utiliser, mais de comparer avec vos propres données et ensuite décider.

280
répondu Paul Dixon 2017-05-23 11:55:03

beaucoup d'autres réponses ici ne prennent pas en compte les caractères unicode (par exemple öäüßй փփ փփ փփ ). Dans ce cas, vous pouvez utiliser ce qui suit:

$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $string);

il y a une classe étrange de caractères dans la gamme \x80-\x9F (juste au-dessus de la gamme 7-bit ASCII de caractères) qui sont techniquement des caractères de contrôle, mais au fil du temps ont été mal utilisés pour les caractères imprimables. Si vous n'avez aucun problème avec ceux-ci, alors vous pouvez utiliser:

$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $string);

Si vous souhaitez également supprimer les sauts de ligne, retour chariot, tabulation, les espaces insécables, et les doux traits d'union, vous pouvez utiliser:

$string = preg_replace('/[\x00-\x1F\x7F-\xA0\xAD]/u', '', $string);

notez que vous devez utilisez des guillemets simples pour les exemples ci-dessus.

si vous souhaitez tout supprimer sauf les caractères ASCII imprimables de base (tous les caractères de l'exemple ci-dessus seront supprimés), vous pouvez utiliser:

$string = preg_replace( '/[^[:print:]]/', '',$string);

pour référence voir http://www.fileformat.info/info/charset/UTF-8/list.htm

130
répondu Dalin 2017-02-07 14:40:53

vous pouvez utiliser les classes de caractères

/[[:cntrl:]]+/
24
répondu ghostdog74 2009-07-24 10:57:16

à partir de PHP 5.2, nous avons également accès à filter_var, dont je n'ai pas vu la moindre mention, alors j'ai pensé que je le jetterais là-bas. Pour utiliser filter_var pour supprimer les caractères non imprimables < 32 et > 127, vous pouvez faire:

filtrer les caractères ASCII en dessous de 32

$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW);

filtrer les caractères ASCII au-dessus de 127

$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_HIGH);

la Bande à la fois:

$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH);

vous pouvez aussi html-encoder des caractères bas (saut de ligne, tabulation, etc. cents cinquante et une million neuf cent soixante mille neuf cent vingt"

$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_LOW|FILTER_FLAG_STRIP_HIGH);

il y a aussi des options pour enlever le HTML, nettoyer les e-mails et les URLs, etc. Donc, beaucoup d'options pour la désinfection (rayer les données) et même la validation (retourner false si pas valide plutôt que silencieusement stripping).

assainissement: http://php.net/manual/en/filter.filters.sanitize.php

Validation: http://php.net/manual/en/filter.filters.validate.php

cependant, il y a toujours le problème, que le FILTER_FLAG_STRIP_LOW va supprimer les retours newline et carriage, qui pour un textarea sont des caractères tout à fait valides...donc certaines réponses Regex, je suppose, sont encore nécessaires à certains moments, par exemple après avoir examiné ce fil, je prévois de le faire pour les textareas:

$string = preg_replace( '/[^[:print:]\r\n]/', '',$input);

Cela semble plus lisible que un certain nombre de regexes qui supprimés par la plage numérique.

21
répondu Kevin Nelson 2015-03-10 18:27:36

c'est plus simple:

$string = preg_replace( '/[^[: cntrl:]]/',", $string);

16
répondu jipipayo 2017-02-23 09:14:50

toutes les solutions fonctionnent partiellement, et même en dessous ne couvre probablement pas tous les cas. Mon problème était d'essayer d'insérer une chaîne dans une table mysql utf8. La chaîne (et ses octets) étaient toutes conformes à utf8, mais avaient plusieurs mauvaises séquences. Je suppose que la plupart d'entre eux étaient du contrôle ou du formatage.

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;
}

pour exacerber davantage le problème est la table vs. server vs. connection vs. rendering du contenu, comme parlé d'un peu ici

13
répondu Wayne Weibel 2017-05-23 11:47:31

ma version compatible UTF-8:

preg_replace('/[^\p{L}\s]/u','',$value);

9
répondu cedivad 2012-05-06 12:56:42

vous pouvez utiliser un express régulier pour supprimer tout sauf les caractères que vous souhaitez conserver:

$string=preg_replace('/[^A-Za-z0-9 _\-\+\&]/','',$string);

remplace tout ce qui n'est pas (^) les lettres A-Z ou A-z, les nombres 0-9, espace, underscore, hypen, plus et ampersand - avec rien (i.e. supprimer).

6
répondu Richy B. 2009-07-24 10:50:59
preg_replace('/(?!\n)[\p{Cc}]/', '', $response);

cela supprimera tous les caractères de contrôle ( http://uk.php.net/manual/en/regexp.reference.unicode.php ) laissant les caractères \n . D'après mon expérience, les caractères de contrôle sont ceux qui causent le plus souvent des problèmes d'impression.

4
répondu Gajus 2013-03-01 11:06:52

la réponse de @PaulDixon est complètement erroné , car il supprime l'imprimable caractères ASCII étendus 128-255! a été partiellement corrigé. Je ne sais pas pourquoi il veut toujours supprimer 128-255 d'un ensemble ascii de 127 chars 7 bits car il n'a pas les caractères ASCII étendus.

mais finalement il était important de ne pas supprimer 128-255 parce que par exemple chr(128) ( \x80 ) est le signe d'euro en 8-bit ASCII et de nombreuses polices UTF-8 dans Windows afficher un signe d'euro et Android en ce qui concerne mon propre test.

et il tuera beaucoup de caractères UTF-8 Si vous supprimez les caractères ASCII 128-255 d'une chaîne UTF-8 (probablement les octets de départ d'un caractère UTF-8 à plusieurs octets). Alors ne fais pas ça! Ce sont des caractères entièrement légaux dans tous les systèmes de fichiers actuellement utilisés. la seule gamme réservée est 0-31 .

utilisez plutôt ceci pour supprimer les caractères non imprimables 0-31 et 127:

$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);

Il travaille en ASCII et UTF-8 parce que les deux partagent le même contrôle de l'ensemble de la gamme .

Le le plus rapide slower1 alternative sans l'aide d'expressions régulières:

$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 vous voulez conserver tous les caractères blancs \t , \n et \r , puis supprimer chr(9) , chr(10) et chr(13) de cette liste. Note: l'espace habituel est chr(32) donc il reste dans le résultat. Décidez vous-même si vous souhaitez supprimer l'espace insécable chr(160) , car il peut causer des problèmes.

1 testé par @PaulDixon et vérifié par moi-même.

3
répondu mgutt 2017-05-23 12:10:43

Que diriez-vous de:

return preg_replace("/[^a-zA-Z0-9`_.,;@#%~'\"\+\*\?\[\^\]$\(\)\{\}\=\!\<\>\|\:\-\s\\]+/", "", $data);

me donne le contrôle complet de ce que je veux inclure

2
répondu sdfor 2015-04-08 18:17:39

anwser marqué est parfait mais il manque le caractère 127 (DEL) qui est aussi un caractère non imprimable

ma réponse serait

$string = preg_replace('/[\x00-\x1F\x7f-\xFF]/', '', $string);
1
répondu Mubashar Ahmad 2013-08-08 03:54:49

"cedivad" résolu le problème pour moi avec le résultat persistant de Swedish chars ÅÄÖ.

$text = preg_replace( '/[^\p{L}\s]/u', '', $text );

Merci!

0
répondu Andreas Ek 2015-03-14 12:07:11

pour tous ceux qui cherchent encore comment faire ceci sans enlever les caractères non imprimables, mais plutôt les échapper, j'ai fait ceci pour aider. N'hésitez pas à améliorer! Les caractères sont échappés à \\x[a-F0-9][a-F0-9].

Appel de la sorte:

$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));
    }
?>
0
répondu DropItLikeItsHot 2017-12-28 18:22:14

j'ai résolu le problème pour UTF8 en utilisant https://github.com/neitanod/forceutf8

use ForceUTF8\Encoding;

$string = Encoding::fixUTF8($string);
0
répondu mnv 2018-07-03 08:55:51

ça a marché pour moi. J'ai dû convertir une chaîne de n'importe quelle sorte qui était un titre aléatoire en une balle pour SEO.

function string2Slug($str){

    $str = trim($str);
    $str = str_replace(" ","_",$str);
    $temp = explode("\u",$str);
    $str = '';
    foreach ($temp as $bit) {
        $str .= substr($bit,4);
    }

    $str = str_replace("'","",$str);
    $str = str_replace("\"","",$str);
    $str = str_replace("\","",$str);
    $str = str_replace("\/","",$str);
    $str = str_replace("/","",$str);
    $str = str_replace("?","",$str);
    $str = str_replace("#","",$str);
    $str = str_replace("&","",$str);
    $str = str_replace("%","",$str);
    $str = str_replace("!","",$str);

    return $str;

}
-1
répondu Jy Smt 2017-06-07 15:27:48