从 PHP 字符串中删除控制字符

Posted

技术标签:

【中文标题】从 PHP 字符串中删除控制字符【英文标题】:Remove control characters from PHP string 【发布时间】:2010-12-02 15:27:01 【问题描述】:

如何(如 STX)?我玩过

preg_replace("/[^a-zA-Z0-9 .\-_;!:?äÄöÖüÜß<>='\"]/","",$pString)

但发现它删除了很多。有没有办法删除 only 控制字符?

【问题讨论】:

以下链接可能对您有所帮助:ASCII Characters TablePOSIX refrenceRegular expressions 【参考方案1】:

如果您的意思是控制字符 first 32 ascii characters and \x7F(包括回车等!),那么这将起作用:

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

(注意单引号:用双引号使用\x00 会导致解析错误,不知何故。)

换行符和回车符(通常写成\r\n)可以这样保存:

preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $input);

我必须说我认为Bobby's answer 更好,因为[:cntrl:][\x00-\x1F\x7F] 更好地传达了代码的功能。

警告: ereg_replacephp >= 5.3.0 中已弃用并在 PHP >= 7.0.0 中被删除!请使用 preg_replace 而不是 ereg_replace

preg_replace('/[[:cntrl:]]/', '', $input);

【讨论】:

感谢 KB22。请注意,当您接受我的回答时,我的正则表达式不正确。请查看更新版本。 遗憾的是 ereg_replace 在 PHP 5.3 中已被弃用,mb 版本比 preg_replace 慢。使用 preg_replace 有一种更简洁的方法,在我的测试中,它比上面的方法要快得多(处理数十万个项目时快 1%):preg_replace('/[\pCc] /', '', $input); 另外,preg_replace('/[[:cntrl:]]/', '', $input);为我工作得很好(php 5.2.6)。 不适合我,这个字符串 >>"Rua Enette Dubard, 806 - Loja 2" 被转换成这个 >> "Rua Eee Dubad, 806 - Loja 2" 并且回车字符仍然存在. 并不是说你也想保存标签“\t”。我发现了这个问题,因为我在我的数据库中得到了 \x1D。【参考方案2】:

对于 Unicode 输入,这将从您的输入文本中删除所有控制字符、未分配的、私人使用的、格式设置和代理代码点(也不是空格字符,例如制表符、换行符)。我用它来从我的输入中删除所有不可打印的字符。

<?php
$clean = preg_replace('/[^\PC\s]/u', '', $input);

有关\pC 的更多信息,请参阅http://www.regular-expressions.info/unicode.html#category

【讨论】:

你为什么用\PC而不是\pC 我们必须使用否定字符类来避免删除空格(因为它们被认为是不可见的),这意味着我们需要使用\pC的逆形式 这正是您将用户输入发送到 Authorize.net API 时所需要的。以防其他人遇到无效的 XML 字符错误。 嗨@ChrisRosillo,我们使用\pC 的逆形式,即\PC,所以\pC 匹配控制字符,\PC 匹配所有非控制字符。然后我们使用否定字符类[^..] 来表示匹配/替换任何“不是[不是控制字符或空格]”的东西。所以这是一种双重否定。 @syl.fabre 关于括号:“如果只用 \p 或 \P 指定了一个字母,则它包括以该字母开头的所有属性。在这种情况下,在没有否定的情况下, 转义序列中的大括号是可选的"【参考方案3】:

PHP 确实支持 POSIX-Classes,因此您可以使用 [:cntrl:] 代替一些花哨的字符魔法:

ereg_replace("[:cntrl:]", "", $pString);

编辑:

在 5.3 中可能需要额外的一对方括号。

ereg_replace("[[:cntrl:]]", "", $pString);

【讨论】:

PHP 确实支持 POSIX,使用 ereg 函数而不是 preg:nl2.php.net/manual/en/book.regex.php 测试了这个,POSIX-Classes 似乎不起作用。无论如何,谢谢你的提示! 我必须纠正自己,更准确地说:ereg 确实有效。 在我的测试中,这仅在向语句添加额外的方括号时才有效,如下所示:ereg_replace("[[:cntrl:]]", "", $pString); PHP 5.3.5. 由于ereg_replace 在 PHP 7.0 中被删除,对于 PHP > 7.0 它应该是:preg_replace("/[[:cntrl:]]/", "", $input);【参考方案4】:

为了保留控制字符但使它们与 JSON 兼容,我不得不这样做

$str = preg_replace(
    array(
        '/\x00/', '/\x01/', '/\x02/', '/\x03/', '/\x04/',
        '/\x05/', '/\x06/', '/\x07/', '/\x08/', '/\x09/', '/\x0A/',
        '/\x0B/','/\x0C/','/\x0D/', '/\x0E/', '/\x0F/', '/\x10/', '/\x11/',
        '/\x12/','/\x13/','/\x14/','/\x15/', '/\x16/', '/\x17/', '/\x18/',
        '/\x19/','/\x1A/','/\x1B/','/\x1C/','/\x1D/', '/\x1E/', '/\x1F/'
    ), 
    array(
        "\u0000", "\u0001", "\u0002", "\u0003", "\u0004",
        "\u0005", "\u0006", "\u0007", "\u0008", "\u0009", "\u000A",
        "\u000B", "\u000C", "\u000D", "\u000E", "\u000F", "\u0010", "\u0011",
        "\u0012", "\u0013", "\u0014", "\u0015", "\u0016", "\u0017", "\u0018",
        "\u0019", "\u001A", "\u001B", "\u001C", "\u001D", "\u001E", "\u001F"
    ), 
    $str
);

(JSON 规则规定:“所有 Unicode 字符都可以放在引号内,但必须转义的字符除外:引号、反斜线和控制字符(U+0000 到 U+001F)。” )

【讨论】:

【参考方案5】:

TLDR 答案

使用这个正则表达式...

/[^\PCc^\PCn^\PCs]/u

像这样……

$text = preg_replace('/[^\PCc^\PCn^\PCs]/u', '', $text);

TLDR 说明

^\PCc不要匹配控制字符。 ^\PCn不要匹配未分配的字符。 ^\PCs不要匹配 UTF-8 无效字符。

工作演示

简单演示:IDEOne Demo

$text = "\u0019hello";
print($text . "\n\n");
$text = preg_replace('/[^\PCc^\PCn^\PCs]/u', '', $text);
print($text);

输出:

(-Broken-Character)hello
hello

替代品

^\PC :仅匹配可见字符。不要匹配任何不可见的字符。 ^\PCc :仅匹配非控制字符。不要匹配任何控制字符。 ^\PCc^\PCn :仅匹配已分配的非控制字符。不要匹配任何控制或未分配的字符。 ^\PCc^\PCn^\PCs :仅匹配已分配且 UTF-8 有效的非控制字符。不匹配任何控制、未分配或 UTF-8 无效字符。 ^\PCc^\PCn^\PCs^\PCf :仅匹配已分配且 UTF-8 有效的非控制、非格式化字符。不匹配任何控制、未分配、格式化或 UTF-8 无效字符。

来源及说明

查看可用于在正则表达式中进行测试的Unicode Character Properties。您应该能够在Microsoft .NET、javascript、Python、Java、PHP、Ruby、Perl、Golang 甚至Adobe 中使用这些正则表达式。了解 Unicode 字符类是非常容易转移的知识,所以我推荐使用它!

这个正则表达式将匹配任何可见的东西,无论是简写还是长写...

\PL\PM\PN\PP\PS\PZ
\PLetter\PMark\PNumber\PPunctuation\PSymbol\PSeparator

通常\p表示我们要匹配的东西,我们使用\P(大写)to indicate something that does not match.但是PHP没有这个功能,所以我们需要在正则表达式中使用^来做手动否定。

一个更简单的正则表达式将是^\PC,但这在删除不可见格式方面可能过于严格。您可能想仔细观察,看看什么是最好的,但其中一种选择应该适合您的需求。

所有可匹配的 Unicode 字符集

如果您想了解任何其他可用的字符集,请查看regular-expressions.info...

\PL\PLetter:来自任何语言的任何类型的信件。 \PLl\PLowercase_Letter:带有大写变体的小写字母。 \PLu\PUppercase_Letter:带有小写变体的大写字母。 \PLt\PTitlecase_Letter:当单词的首字母大写时出现在单词开头的字母。 \PL&amp;\PCased_Letter:以小写和大写形式存在的字母(Ll、Lu 和 Lt 的组合)。 \PLm\PModifier_Letter:一个特殊字符,像字母一样使用。 \PLo\POther_Letter:不区分大小写的字母或表意文字 \PM\PMark:旨在与另一个字符组合的字符(例如重音符号、变音符号、封闭框等)。 \PMn\PNon_Spacing_Mark: 用于与另一个字符组合的字符 不占用额外空间的字符(例如重音、变音等)。 \PMc\PSpacing_Combining_Mark:旨在与占用额外空间的另一个字符组合的字符(许多东方语言中的元音符号)。 \PMe\PEnclosing_Mark:包含与其组合的字符(圆形、方形、键帽等)的字符。 \PZ\PSeparator:任何类型的空格或不可见的分隔符。 \PZs\PSpace_Separator:一个不可见但占用空间的空白字符。 \PZl\PLine_Separator:行分隔符 U+2028。 \PZp\PParagraph_Separator:段落分隔符 U+2029。 \PS\PSymbol:数学符号、货币符号、装饰符号、画框字符等。 \PSm\PMath_Symbol:任何数学符号。 \PSc\PCurrency_Symbol:任何货币符号。 \PSk\PModifier_Symbol:将组合字符(标记)单独作为一个完整字符。 \PSo\POther_Symbol:不是数学符号、货币符号或组合字符的各种符号。 \PN\PNumber:任何脚本中的任何类型的数字字符。 \PNd\PDecimal_Digit_Number:除表意文字之外的任何文字中的数字 0 到 9。 \PNl\PLetter_Number:一个看起来像字母的数字,例如罗马数字。 \PNo\POther_Number:上标或下标数字,或不是数字 0-9 的数字(不包括来自表意文字的数字)。 \PP\PPunctuation:任何类型的标点符号。 \PPd\PDash_Punctuation:任何类型的连字符或破折号。 \PPs\POpen_Punctuation:任何类型的左括号。 \PPe\PClose_Punctuation:任何类型的右括号。 \PPi\PInitial_Punctuation:任何类型的开场白。 \PPf\PFinal_Punctuation:任何类型的结束语。 \PPc\PConnector_Punctuation:一个标点符号,例如连接单词的下划线。 \PPo\POther_Punctuation:任何非破折号、括号、引号或连接符的标点符号。 \PC\POther:不可见的控制字符和未使用的代码点。 \PCc\PControl:ASCII 或 Latin-1 控制字符:0x00–0x1F 和 0x7F–0x9F。 \PCf\PFormat:不可见的格式指示符。 \PCo\PPrivate_Use:保留供私人使用的任何代码点。 \PCs\PSurrogate:UTF-16 编码的代理对的一半。 \PCn\PUnassigned:任何未分配字符的代码点。

【讨论】:

【参考方案6】:

无正则表达式方法

如果您只是对我熟悉的控制字符(32 岁和 127 岁以下)进行切换,试试这个:

 for($control = 0; $control < 32; $control++) 
     $pString = str_replace(chr($control), "", $pString;
 

$pString = str_replace(chr(127), "", $pString;

循环删除了除 DEL 之外的所有内容,我们只是将其添加到末尾。

我认为这对你和脚本来说压力会小很多,然后处理正则表达式和正则表达式库。

更新了无正则表达式的方法

只是为了好玩,我想出了另一种方法。这个是使用一组控制字符来完成的:

$ctrls = range(chr(0), chr(31));
$ctrls[] = chr(127);

$clean_string = str_replace($ctrls, "", $string);

【讨论】:

这怎么比 ereg_replace("[:cntrl:]", "", $pString); ?使用 ereg,PHP 解释器可能会编译比使用 for 循环更有效的中间代码。 ereg_replace 已从 php 5.3.0 中弃用 这是正则表达式可能更具可读性的一种情况。但我喜欢这个答案,因为它可能具有一些性能优势,并且基本上可以在每个 PHP 安装上正常工作。竖起大拇指!

以上是关于从 PHP 字符串中删除控制字符的主要内容,如果未能解决你的问题,请参考以下文章

从控制台中删除单个字符

PHP 删除 Windows ^M 字符

php过滤ascii控制字符

删除Access数据库中所有表中所有字符串字段中的所有控制字符

如何使用php从字符串中删除特殊字符,例如:&)(\ /?

php如何从php中的字符串中删除最后一个字符[重复]