1. ホーム
  2. php

[解決済み] 文字列中の印刷不可能な文字をすべて削除するには?

2022-04-20 14:49:42

質問

0-31と127の文字列を削除する必要があると想像しています。

これを効率的に行うための関数やコードはありますか?

どのように解決するのですか?

7ビットASCII?

もしあなたのターディスが1963年に着陸したばかりで、7ビットの印刷可能なASCII文字が欲しいだけなら、これで0-31と127-255のすべてを切り取ることができます。

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

0-31、127-255の範囲にあるものにマッチし、それを削除します。

8ビット拡張ASCII?

ホットタブ・タイムマシーンに落ちて、80年代に戻ってきたんだ。 もしあなたが何らかの形で8ビットASCIIを使用しているなら、文字を128-255の範囲に収めたいと思うかもしれません。0-31と127を探すだけで、簡単に調整できます。

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

UTF-8ですか?

ああ、21世紀へお帰りなさい。UTF-8でエンコードされた文字列がある場合は /u モディファイア は正規表現で使用することができます

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

これは、0-31と127を削除するだけです。これはASCIIとUTF-8で動作し、両方とも 同じ制御セット範囲 (下記のmguttさんの指摘の通り)。厳密に言えば,これは /u 修飾子を使用します。しかし、他の文字を削除したい場合は、この修飾子があると便利です....

ユニコードを扱う場合は 印刷されない要素が多数ある可能性がある しかし、ここでは簡単なものを考えてみましょう。 ノーブレーク・スペース (u+00a0)

UTF-8の文字列では、これは次のようにエンコードされます。 0xC2A0 . その特定のシーケンスを探して削除することもできますが、その場合は /u 修飾子を付けるだけで \xA0 をキャラクタ・クラスに追加します。

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

追記:str_replaceはどうなんでしょう?

preg_replace はかなり効率的ですが、もしこの操作を何度も行うのであれば、削除したい文字の配列を作成し、下記の mgutt さんの指摘するように str_replace を使うことができます、例えば。

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

直感的には、これは速いように見えますが、必ずしもそうではありません。ランダムなデータでさまざまな文字列の長さのベンチマークを行ったところ、 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

タイミング自体は1万回繰り返した場合のものですが、より興味深いのは相対的な差です。512文字までは、preg_replaceが常に勝っていました。1-8kbの範囲では、str_replaceが僅かに優勢でした。

面白い結果だと思ったので、ここに載せておきます。 重要なのは、この結果を鵜呑みにしてどの方式を使うかを決めるのではなく、自分のデータと照らし合わせて決めることです。