213 votes

Comment supprimer tous les caractères non imprimables d'une chaîne de caractères ?

J'imagine que je dois supprimer les caractères 0-31 et 127.

Existe-t-il une fonction ou un morceau de code permettant de réaliser cette opération de manière efficace ?

464voto

Paul Dixon Points 122033

ASCII 7 bits ?

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

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

Il correspond à tout ce qui se trouve dans les plages 0-31, 127-255 et le supprime.

ASCII étendu à 8 bits ?

Vous êtes tombé dans une machine à remonter le temps, et vous êtes de retour dans les années 80. Si vous disposez d'une forme d'ASCII 8 bits, il est préférable de conserver les caractères dans la plage 128-255. Un ajustement facile - il suffit de chercher 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 de caractères encodée en UTF-8, alors la fonction /u modificateur peut être utilisé sur le regex

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

Cela supprime simplement les valeurs 0-31 et 127. Cela fonctionne en ASCII et en UTF-8, car les deux partagent le même nom. même plage de réglage du contrôle (comme indiqué par mgutt ci-dessous). Strictement parlant, cela fonctionnerait sans l'option /u modificateur. Mais cela facilite la vie si vous voulez supprimer d'autres personnages...

Si vous avez affaire à Unicode, il y a potentiellement de nombreux éléments non imprimables mais considérons un cas simple : ESPACE SANS COUPURE (U+00A0)

Dans une chaîne UTF-8, cela serait codé comme suit 0xC2A0 . Vous pourriez rechercher et supprimer cette séquence spécifique, mais avec la /u 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 effectuez souvent cette opération, vous pouvez construire un tableau des caractères que vous voulez supprimer, et utiliser str_replace comme indiqué par mgutt ci-dessous, par ex.

//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, cela semble être rapide, mais ce n'est pas toujours le cas. Vous devez absolument faire un test pour voir si cela vous fait économiser quelque chose. J'ai fait quelques tests sur une variété de chaînes de caractères avec des données aléatoires, et ce modèle est apparu avec 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 temps sont calculés pour 10000 itérations, mais ce qui est plus intéressant, ce sont les différences relatives. Jusqu'à 512 caractères, je voyais preg_replace toujours gagnant. Dans la gamme 1-8kb, str_replace avait un avantage marginal.

J'ai pensé que c'était un résultat intéressant, donc je l'inclus ici. L'important n'est pas de prendre ce résultat et de l'utiliser pour décider de la méthode à utiliser, mais de le comparer à vos propres données et de décider ensuite.

15 votes

Si vous devez considérer qu'une nouvelle ligne est sûre, changez l'expression en ceci (recherche inversée pour les imprimables) : preg_replace(/[^ \x0A\x20 - \x7E ]/,'',$string) ;

13 votes

@Dalin Il n'existe pas de "caractère UTF-8". Il existe des symboles/caractères Unicode, et UTF-8 est un encodage qui peut les représenter tous. Vous vouliez dire que cela ne fonctionne pas pour les caractères en dehors du jeu de caractères ASCII.

4 votes

Si vous devez faire correspondre un caractère unicode au-dessus de \xFF utiliser \x {####}

161voto

Dalin Points 665

De nombreuses autres réponses ne prennent pas en compte les caractères unicodes (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 personnages dans la gamme \x80-\x9F (juste au-dessus de la gamme de caractères ASCII de 7 bits) qui sont techniquement des caractères de contrôle, mais qui, au fil du temps, ont été utilisés à tort comme caractères imprimables. Si vous n'avez pas de problèmes avec ces caractères, vous pouvez les utiliser :

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

Si vous souhaitez également supprimer les sauts de ligne, les retours de chariot, les tabulations, les espaces insécables et les tirets souples, vous pouvez utiliser :

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

Notez que vous doit utilisez des guillemets simples pour les exemples ci-dessus.

Si vous souhaitez supprimer tout ce qui n'est pas des caractères ASCII imprimables de base (tous les caractères d'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

1 votes

Votre regexp traite bien les caractères UTF8, mais il élimine les caractères "spéciaux" non-UTF8, comme ç, ü et ö. '/[\x00-\x1F\x80-\xC0]/u' les laisse intacts ; mais aussi le signe de la division (F7) et de la multiplication (D7).

1 votes

@Hazar oui vous avez raison \x80 - \xFF trop dépouillé, mais \x80 - \xC0 est encore trop restrictive. Cela laisserait de côté d'autres caractères imprimables comme ©£±. Pour référence, voir utf8-chartable.de

0 votes

Le troisième exemple avec :print : se comporte différemment selon les machines. Il fonctionne sur localhost, mais ne supprime pas les mêmes caractères sur notre serveur live. Le premier exemple a supprimé les chiffres réguliers de ma chaîne sur localhost.

27voto

ghostdog74 Points 86060

Vous pouvez utiliser des classes de caractères

/[[:cntrl:]]+/

1 votes

Mais cela ne m'oblige-t-il pas à utiliser ereg ?

18voto

jipipayo Points 1358

C'est plus simple :

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

5 votes

Cela supprime également les sauts de ligne, les retours chariot et les caractères UTF8.

6 votes

@Dalin Il n'existe pas de "caractère UTF-8". Il existe des symboles/caractères Unicode, et UTF-8 est un encodage qui peut les représenter tous. Vous vouliez dire ces bandes caractères hors de la plage ASCII également.

2 votes

Mange les caractères arabes :)

13voto

cedivad Points 705

Ma version conforme à l'UTF-8 :

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

10 votes

Cela permet de supprimer des caractères comme les guillemets, les parenthèses, etc. Ce sont certainement des caractères imprimables.

0 votes

C'est merveilleux ! il m'a sauvé la vie, je me suis trompé en imprimant des caractères arabes, cela a fonctionné comme un champion :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X