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

2022-08-30 06:26:27

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

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


答案 1

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

$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非常有效,但是如果您经常执行此操作,则可以构建要删除的字符数组,并使用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具有边际优势。

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


答案 2

这里的许多其他答案没有考虑unicode字符(例如öäüßйȝîûηыეமிᚉ⠛ )。在这种情况下,您可以使用以下内容:

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

该范围内有一类奇怪的字符(刚好高于 7 位 ASCII 字符范围),这些字符在技术上是控制字符,但随着时间的推移,它们已被误用于可打印字符。如果您对这些没有任何问题,则可以使用:\x80-\x9F

$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


推荐