从 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_replace
在 php >= 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&
或 \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 字符串中删除控制字符的主要内容,如果未能解决你的问题,请参考以下文章