代码之家  ›  专栏  ›  技术社区  ›  Stewart Robinson

如何删除字符串中所有不可打印的字符?

  •  138
  • Stewart Robinson  · 技术社区  · 16 年前

    我想我需要去掉字符0-31和127,

    是否有一个函数或一段代码可以有效地执行此操作。

    17 回复  |  直到 16 年前
        1
  •  290
  •   Community CDub    8 年前

    7位ASCII?

    如果您的tardis于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 modifier 可用于regex

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

    这只会删除0-31和127。这在ascii和utf-8中有效,因为它们都共享 same control set range (如下面的mgutt所述)。严格来说,如果没有 U 修饰语。但如果你想去掉其他的字符,这会让生活更容易…

    如果你在处理unicode,有 potentially many non-printing elements ,但让我们考虑一个简单的问题: NO-BREAK SPACE (U+00A0)

    在UTF-8字符串中,这将被编码为 0xC2A0 . 您可以查找并删除该特定序列,但使用 U 修饰符就位后,只需添加 \xA0 到角色类:

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

    附录:Str_Replace怎么样?

    preg ou replace非常有效,但是如果您经常执行此操作,您可以构建一个要删除的字符数组,并使用下面mgutt提到的str ou 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个字符,我看到普瑞格取代阿尔韦获胜。在1-8kb范围内,str_replace具有边缘优势。

    我认为这是一个有趣的结果,所以把它包括在这里。 重要的是不要拿这个结果来决定使用哪种方法,而是要根据自己的数据进行基准测试,然后再决定。

        2
  •  132
  •   Dalin    8 年前

    这里的许多其他答案没有考虑到Unicode字符(例如_¶_·_ ___»_·_ __?___)。在这种情况下,您可以使用以下内容:

    $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

        3
  •  25
  •   ghostdog74    16 年前

    可以使用字符类

    /[[:cntrl:]]+/
    
        4
  •  23
  •   Kevin Nelson    10 年前

    从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,而不是静默剥离)。

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

    验证: http://php.net/manual/en/filter.filters.validate.php

    但是,仍然存在这样的问题,即过滤器_flag_strip_low将删除换行符和回车符,这对于文本区域来说是完全有效的字符……因此,我想某些regex答案有时仍然是必要的,例如,在检查完此线程后,我计划对文本区域执行此操作:

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

    这似乎比由数字范围去除的一些正则表达式更具可读性。

        5
  •  18
  •   Otto    8 年前

    这更简单:

    $string=preg_替换( '/[^[:cntrl:]/','$string);

        6
  •  14
  •   Community CDub    8 年前

    所有的解决方案都是部分工作的,即使是下面的解决方案也可能无法涵盖所有的情况。我的问题是试图在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;
    }
    

    为了进一步加剧这个问题,表、服务器、连接和呈现内容是 talked about a little here

        7
  •  9
  •   cedivad    13 年前

    我的符合UTF-8的版本:

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

        8
  •  6
  •   Richy B.    16 年前

    您可以使用常规Express删除除要保留的字符以外的所有内容:

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

    将所有非(^)字母a-z或a-z、数字0-9、空格、下划线、hypen、加号和号-替换为空(即删除它)。

        9
  •  5
  •   Gajus    12 年前
    preg_replace('/(?!\n)[\p{Cc}]/', '', $response);
    

    这将删除所有控制字符( http://uk.php.net/manual/en/regexp.reference.unicode.php 离开 \n 换行符。根据我的经验,控制字符是最经常引起打印问题的字符。

        10
  •  3
  •   Community CDub    8 年前

    这个 answer of @PaulDixon 完全错误 ,因为它 删除可打印的 extended ASCII characters 128—255! 已部分更正。我不知道他为什么还想从127个字符的7位ASCII集中删除128-255,因为它没有扩展的ASCII字符。

    但最后,重要的是不要删除128-255,因为例如 chr(128) ( \x80 )是8位ASCII和许多UTF-8字体在Windows中的欧元符号吗? display a euro sign 关于我自己的测试。

    如果从utf-8字符串(可能是多字节utf-8字符的起始字节)中删除ASCII字符128-255,它将杀死许多utf-8字符。所以不要这样做!它们在所有当前使用的文件系统中都是完全合法的字符。 The only reserved range is 0-31 .

    而是使用此命令删除不可打印的字符0-31和127:

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

    使用ASCII和UTF-8 因为两者都分享 same control set range .

    这个 最快的 不使用正则表达式的较慢备选方案:

    $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测试并由本人验证。

        11
  •  2
  •   George Brighton    10 年前

    怎么样:

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

    完全控制我想要包括的内容

        12
  •  1
  •   Mubashar    12 年前

    标记的anwser是完美的,但它缺少字符127(del),该字符也是不可打印的字符

    我的答案是

    $string = preg_replace('/[\x00-\x1F\x7f-\xFF]/', '', $string);
    
        13
  •  0
  •   Andreas Ek    10 年前

    “Cedivad”用瑞典字符和的持久结果为我解决了这个问题。

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

    谢谢!

        14
  •  0
  •   DropItLikeItsHot    7 年前

    对于仍在寻找如何在不删除不可打印字符的情况下执行此操作的任何人,我之所以这样做是为了帮助他们。请随时改进它!字符转义到\\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));
        }
    ?>
    
        15
  •  0
  •   Nick    7 年前

    我解决了使用utf8的问题 https://github.com/neitanod/forceutf8

    use ForceUTF8\Encoding;
    
    $string = Encoding::fixUTF8($string);
    
        16
  •  0
  •   Junaid Masood    6 年前

    从输入字符串中除去所有非ASCII字符

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

    该代码删除十六进制范围0-31和128-255中的任何字符,只在生成的字符串中保留十六进制字符32-127,在本例中我称之为$result。

        17
  •  -1
  •   Michael Nelles Kranti Brid    8 年前

    这对我有用。我必须将任意标题的字符串转换为seo的slug。

    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;
    
    }
    
    推荐文章