PHP:文字列内の印刷できない文字をすべて削除する方法は?


回答:


354

7ビットASCII?

Tardisが1963年に上陸したばかりで、7ビットの印刷可能なASCII文字が必要な場合は、次のようにして0〜31と127〜255のすべてをリッピングできます。

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

0〜31、127〜255の範囲のすべてに一致し、削除されます。

8ビット拡張ASCII?

あなたはHot Tub Time Machineに陥り、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修飾子なしで機能します。しかし、他の文字を削除したい場合は、簡単になります...

Unicodeを扱っている場合、潜在的に多くの非印刷要素が存在しますが、単純なものを考えてみましょう:NO-BREAK SPACE(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

タイミング自体は10000回の反復に対するものですが、さらに興味深いのは相対的な違いです。最大512文字で、preg_replaceが常に勝っていました。1〜8 kbの範囲では、str_replaceに限界エッジがありました。

面白い結果だと思ったのでここに入れておきます。重要なことは、この結果を使用して、使用する方法を決定するために使用するのではなく、独自のデータに対してベンチマークしてから決定することです。


14
改行セーフを考慮する必要がある場合は、式を次のように変更します(逆に印刷可能なものを検索します)。preg_replace(/ [^ \ x0A \ x20- \ x7E] /、 ''、$ string);
Nick

12
@ダリン「UTF-8キャラクター」というものはありません。Unicodeの記号/文字があり、UTF-8はそれらすべてを表すことができるエンコーディングです。これは、ASCII文字セット以外の文字では機能しないと言うつもりでした。
Mathias Bynens 2012

3
\ xFFを超えるUnicode文字に一致させる必要がある場合は、\ x {####}を使用してください
Peter Olson

印刷できない文字である\ x7F(127)を逃した
Mubashar 2013

これはアラビア文字を削除します、悪い解決策。
アイマンフセイン

141

ここでの他の回答の多くはユニコード文字を考慮していません(例öäüßйȝîûηыეமிᚉ⠛)。この場合、以下を使用できます。

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

範囲内\x80-\x9F(7ビットASCII範囲の文字より少し上)には、技術的に制御文字である奇妙なクラスの文字がありますが、長い間、印刷可能な文字として誤用されてきました。これらに問題がない場合は、以下を使用できます。

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

改行、キャリッジリターン、タブ、改行しないスペース、ソフトハイフンも削除したい場合は、次を使用できます。

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

上記の例では、一重引用符を使用する必要があることに注意してください。

基本的な印刷可能なASCII文字以外のすべてを削除したい場合(上記の例の文字はすべて削除されます)、次のように使用できます。

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

参照については、http://www.fileformat.info/info/charset/UTF-8/list.htmを参照してください


1
正規表現はUTF8文字を適切に処理します。ただし、UTF8以外の「特殊」文字は削除されます。ç、ü、öなど。'/[\x00-\x1F\x80-\xC0]/u'それらをそのまま残します。除算(F7)と乗算(D7)の記号も含まれます。
ハザル

@ハザールはい、あなたは正しいです\ x80- \ xFFはあまり取り除かれましたが、\ x80- \ xC0はまだ制限が厳しすぎます。これは、©£±のような他の印刷可能な文字を見逃します。参考のために、utf8-chartable.de
Dalin

1
@TimMaloneは、PHPがこれらの文字シーケンスを展開するためです。php.net / manual / en / 正規表現は、指定しようとしている範囲を認識しません。
Dalin、2016年

1
7Fはどうですか?それはいけません\x7F-\x9Fか?
ベル:

1
私はたくさん試しましたが、正規表現からmb_、htmlspecialcharsなど、PHPで利用可能なすべてのエンコーディング関数を試しました。作業に投資してくれたおかげで、制御文字は何も削除されませんでした。
ジョン

29

PHP 5.2以降、filter_varにもアクセスできるようになりました。これについては言及していません。filter_varを使用して、印刷できない文字<32および> 127を取り除くには、次のようにします。

32未満のASCII文字をフィルタリングする

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

127を超えるASCII文字をフィルタリングする

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

両方を取り除く:

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

高い文字を削除しながら、低い文字(改行、タブなど)をHTMLエンコードすることもできます。

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

HTMLを削除したり、電子メールやURLをサニタイズしたりするためのオプションもあります。そのため、サニタイズ(データを削除)や検証(サイレントに削除するのではなく、有効でない場合はfalseを返す)のための多くのオプションがあります。

サニタイズ: http : //php.net/manual/en/filter.filters.sanitize.php

検証: http : //php.net/manual/en/filter.filters.validate.php

ただし、FILTER_FLAG_STRIP_LOWが改行とキャリッジリターンを取り除くという問題がまだあります。これは、textareaの場合は完全に有効な文字です。したがって、たとえばこれを確認した後、一部の正規表現の回答がまだ必要な場合があります。スレッド、私はtextareasに対してこれを行う予定です:

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

これは、数値の範囲で取り除かれた多くの正規表現よりも読みやすいようです。



18

これはより簡単です:

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


5
これにより、改行、キャリッジリターン、UTF8文字も削除されます。
Dalin

5
@ダリン「UTF-8キャラクター」というものはありません。Unicodeの記号/文字があり、UTF-8はそれらすべてを表すことができるエンコーディングです。これは、ASCII範囲外の文字も削除することを意味します。
Mathias Bynens

1
アラビア語の文字を食べます:)
Rolf

16

すべてのソリューションは部分的に機能し、以下でもすべてのケースをカバーできるわけではありません。私の問題は、utf8 mysqlテーブルに文字列を挿入することでした。文字列(およびそのバイト)はすべてutf8に準拠していましたが、いくつかの不良シーケンスがありました。私はそれらのほとんどが制御またはフォーマットであったと思います。

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

ここで少し説明したように、問題をさらに悪化させるのは、テーブルとサーバーと接続とコンテンツのレンダリングです。


1
私のすべての単体テストに合格した唯一のもの、素晴らしい!
Korri

\ xE2 \ x80 [\ xA4- \ xA8](または226.128。[164-168])-誤り、シーケンスには次の印刷可能な記号が含まれます:Unicode文字 'ONE DOT LEADER'(U + 2024)、Unicode文字 'TWO DOT LEADER '(U + 2025)、Unicode文字' HORIZONTAL ELLIPSIS '(U + 2026)、Unicode文字' HYPHENATION POINT '(U + 2027)。また、印刷できないのは、Unicode文字「LINE SEPARATOR」(U + 2028)のみです。次のものも印刷できません:Unicode文字 'PARAGRAPH SEPARATOR'(U + 2029)。したがって、シーケンスを\ xE2 \ x80 [\ xA8- \ xA9] \ xE2 \ x80 [\ xA8- \ xA9]に置き換えて、LINE SEPARATORとPARAGRAPH SEPARATORを削除します。
MingalevME 2018年

これは私がこれまでに見つけた最善の解決策ですが$s = preg_replace('/(\xF0\x9F[\x00-\xFF][\x00-\xFF])/', ' ', $s);、すべての絵文字がmysqlをめちゃくちゃにしていたため、追加する必要がありました
Joe Black

9

私のUTF-8準拠バージョン:

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


7
これにより、引用符や角括弧などの文字がうまく削除されます。これらは確かに印刷可能な文字です。
Gajus 2014年

これは素晴らしい!それは私の人生を救い、アラビア文字の印刷中にめちゃくちゃになり、チャンピオンのように機能しました:)
クリシュナ

6

正規表現を使用して、保持したい文字以外のすべてを削除できます。

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

(^)文字AZまたはaz、数字0〜9、スペース、アンダースコア、ハイフン、プラス、アンパサンド以外のすべてを置き換えます(つまり、削除します)。


5
preg_replace('/(?!\n)[\p{Cc}]/', '', $response);

これにより、すべての制御文字(http://uk.php.net/manual/en/regexp.reference.unicode.php)が削除され、\n改行文字が残ります。私の経験では、制御文字は印刷の問題を最も頻繁に引き起こすものです。


1
それは私にぴったりです!/uUTF-8文字だけを追加しました。最初の部分(?!\n)が何をするか説明してもらえますか?
Marcio Mazzucato

4

入力文字列からすべての非ASCII文字を削除するには

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

このコードは、16進数の範囲0〜31および128〜255のすべての文字を削除し、結果の文字列に16進数の32〜127のみを残します。この例では、$ resultと呼んでいます。


3

@PaulDixon答え完全に間違っています。印刷可能な 拡張ASCII文字 128〜255が削除されるためです。部分的に修正されました。拡張ASCII文字がないため、127文字の7ビットASCIIセットから128-255を削除する理由を私は知りません。

しかし、最後に128-255を削除しないことが重要でした。たとえば、chr(128)\x80)は8ビットASCII のユーロ記号であり、Windowsの多くのUTF-8フォントは、自分のテストに関してユーロ記号とAndroidを表示します。

そして、UTF-8文字列(おそらくマルチバイトUTF-8文字の開始バイト)からASCII文字128〜255を削除すると、多くのUTF-8文字が削除されます。だから、それをしないでください!それらは、現在使用されているすべてのファイルシステムで完全に正当な文字です。予約されている範囲は0〜31のみです。

代わりにこれを使用して、印刷できない文字0〜31および127を削除します。

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

どちらも同じ制御セット範囲を共有するため、ASCIIとUTF-8動作します

正規表現を使用しない、最も遅い slowの代替案:

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

すべての空白文字\t\nおよびを保持する場合は、このリストから、およびを\r削除します。注:通常の空白は、結果に残るようにするためです。問題が発生する可能性があるため、改行しないスペースを削除するかどうかを決定します。chr(9)chr(10)chr(13)chr(32)chr(160)

@ @PaulDixonによってテストされ、自分で検証されました。


2

どのように:

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

含めるものを完全に制御できます


0

マークされたanwserは完璧ですが、印刷できない文字である127(DEL)がありません。

私の答えは

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

この答えも間違っています。参照:stackoverflow.com/a/42058165/318765
mgutt

上記の回答は、「削除」文字のみを追加する元の回答への賛辞でした。
ムバシャル

0

「cedivad」はスウェーデンのcharsÅÄÖの永続的な結果で問題を解決しました。

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

ありがとう!


0

印刷不可能な文字を削除せずにエスケープする方法をまだ探している人のために、それらをエスケープするために、私はこれを手助けするために作りました。自由に改善してください!文字は\\ x [A-F0-9] [A-F0-9]にエスケープされます。

次のように呼び出します。

$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

https://github.com/neitanod/forceutf8を使用してUTF8の問題を解決しました

use ForceUTF8\Encoding;

$string = Encoding::fixUTF8($string);

1
このlibは、UTF-8アクセント付き文字とUTF-8絵文字を「?」に変換します シンボル。残念ながらかなり深刻な問題です。
ChristoKiwi 2018

0

選択した回答への正規表現がUnicodeで失敗する:0x1d(php 7.4を使用)

解決策:

<?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文字列は、改行以外のすべての非表示文字を削除します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.