如何从字符串中删除所有非可打印字符?

210

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

是否有可以高效完成此操作的函数或代码片段?

18个回答

5
@PaulDixon的答案已经部分修正,因为它删除了可打印的扩展ASCII字符128-255。我不知道他为什么还想从127个字符的7位ASCII集中删除128-255,因为它没有扩展ASCII字符。
但最终重要的是不要删除128-255,因为例如chr(128)(\x80)是8位ASCII码中的欧元符号,许多UTF-8字体在Windows上显示欧元符号,在我的测试中也是如此。
如果从UTF-8字符串中删除ASCII字符128-255,则会破坏许多UTF-8字符(可能是多字节UTF-8字符的起始字节)。因此,请不要这样做!它们在所有当前使用的文件系统中都是完全合法的字符。唯一保留的范围是0-31
相反,请使用以下内容删除不可打印字符0-31和127:
$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);

它能够在ASCII和UTF-8下工作,因为两者都使用了相同的控制字符集范围

不使用正则表达式的最快较慢¹替代方案:

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

3

在 PHP 7.4 中,使用正则表达式选择答案时,Unicode 编码为 0x1d 的字符会失败。

解决方案:

<?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字符串删除除换行符外的所有不可见字符


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

给我完全控制想要包含什么。

1

如果您仍在寻找如何不删除不可打印字符而是转义它们来执行此操作的方法,我制作了这个工具以帮助您。欢迎改进!字符被转义为 \\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

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

我的答案是:

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

这个答案也是错误的。请参考:https://dev59.com/cnM_5IYBdhLWcg3w43pt#42058165 - mgutt
上面的回答是对原始回答的赞美,只是增加了“删除”字符。 - Mubashar

0
"

"cedivad" 为我解决了一个问题,使得瑞典字符 ÅÄÖ 的结果持久化。

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

谢谢!


0
我想知道为什么没有人提到这个问题:
1. 由于PHP函数假设每个字节都是一个字符,所以我们必须使用mb_函数的对应方法。
如果你有来自世界各地的用户,你必须考虑这一点,因为如果你坚持使用PHP的preg_replace函数,它会丢弃CJK、阿拉伯、格鲁吉亚字符。
2. 我遇到的另一个问题是,mb_函数要求模式只能是一个字符串,而不能像/pattern/im这样用开始/结束修饰符包裹起来。
另一个注意事项:如果你使用^[:print:],它只会保留0x20-0x7e之间的所有字符,所以会丢弃所有大于0x800的字符;但如果你使用[:cntrl:],它会丢弃0x00-0x1f和0x7f(DEL字符),所以你可以轻松保留所有扩展ASCII字符。
我的工作代码是这样的:
$pattern = "[[:cntrl:]".PHP_EOL."]";
mb_ereg_replace($pattern, '', $text);

-1

2
这个库将UTF-8带重音的字符和UTF-8表情符号转换为“?”符号。 非常严重的问题,不幸的是。 - ChristoKiwi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接