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

时间:2009-07-24 10:48:17

标签: php utf-8 ascii

我想我需要删除字符0-31和127,

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

18 个答案:

答案 0 :(得分:301)

7位ASCII?

如果您的Tardis刚刚在1963年登陆,并且您只想要7位可打印的ASCII字符,那么您可以使用以下方式删除0-31和127-255之间的所有内容:

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

它匹配范围0-31,127-255中的任何内容并将其删除。

8位扩展ASCII?

你掉进了热水浴缸时光机,你又回到了八十年代。 如果您有某种形式的8位ASCII,那么您可能希望将字符保持在128-255范围内。一个简单的调整 - 只需寻找0-31和127

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

UTF-8?

啊,欢迎回到21世纪。如果你有一个UTF-8编码的字符串,那么/u modifier可以在正则表达式上使用

$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_replace非常有效,但是如果你正在做很多这样的操作,你可以构建一个你要删除的字符数组,并使用str_replace,如下面的mgutt所示,例如

//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-8kb范围内,str_replace具有边缘优势。

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

答案 1 :(得分:134)

这里的许多其他答案都没有考虑到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

答案 2 :(得分:26)

你可以使用角色类

/[[:cntrl:]]+/

答案 3 :(得分:23)

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

这似乎比数字范围剥离的许多正则表达式更具可读性。

答案 4 :(得分:18)

这更简单:

  

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

答案 5 :(得分:15)

所有解决方案都有部分工作,甚至可能不会涵盖所有情况。我的问题是尝试将字符串插入到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

答案 6 :(得分:9)

我的UTF-8兼容版本:

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

答案 7 :(得分:6)

您可以使用常规快递删除除了您希望保留的字符之外的所有内容:

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

取代所有不是(^)字母A-Z或a-z,数字0-9,空格,下划线,超广,加号和&符号 - 没有任何东西(即删除它)。

答案 8 :(得分:5)

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

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

答案 9 :(得分:3)

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

但最后重要的是不要删除128-255,因为例如chr(128)\x80)是8位ASCII中的欧元符号和Windows中的许多UTF-8字体{{3}和Android有关我自己的测试。

如果从UTF-8字符串中删除ASCII字符128-255(可能是多字节UTF-8字符的起始字节),它将终止许多UTF-8字符。所以不要这样做!它们是所有当前使用的文件系统中完全合法的字符。 display a euro sign

而是使用它来删除不可打印的字符0-31和127:

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

适用于ASCII和UTF-8 ,因为它们共享The only reserved range is 0-31

最快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测试并由我自己验证。

答案 10 :(得分:2)

怎么样:

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

让我完全控制我想要包含的内容

答案 11 :(得分:1)

标记答案是完美的,但它错过了字符127(DEL),这也是一个不可打印的字符

我的回答是

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

答案 12 :(得分:1)

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

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

该代码删除了十六进制范围0-31和128-255中的所有字符,只在结果字符串中保留了十六进制字符32-127,在本示例中我将其称为$ result。

答案 13 :(得分:0)

“cedivad”为我解决了这个问题,瑞典人ÅÄÖ持续留下了结果。

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

谢谢!

答案 14 :(得分:0)

对于那些仍然在寻找如何在不删除不可打印字符的情况下执行此操作的人,而是在逃避它们时,我这样做是为了帮助。随意改进它!字符转义为\\ x [A-F0-9] [A-F0-9]。

这样打电话:

string
$escaped = EscapeNonASCII($string);

$unescaped = UnescapeNonASCII($string);

答案 15 :(得分:0)

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

Config config = Config.toClusterMode(this.config);
String stateMgrClass = Context.stateManagerClass(config); // get state manager instance
IStateManager stateMgr = null;
try {
    stateMgr = ReflectionUtils.newInstance(stateMgrClass);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
    e.printStackTrace();
}
stateMgr.initialize(config);
return stateManagerAdaptor = new SchedulerStateManagerAdaptor(stateMgr, 1000); // 5000: timeout

答案 16 :(得分: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;

来自: UTF 8 String remove all invisible characters except newline

答案 17 :(得分:-1)

这对我有用。我不得不将一个随机标题的字符串转换成一个用于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;

}