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

时间:2009-09-30 12:45:53

标签: php regex string

如何从PHP字符串中删除STX等控制字符?我玩了

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

但发现它删除的方式很多。有没有办法删除 控制字符?

6 个答案:

答案 0 :(得分:95)

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

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

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

换行和回车(通常写为\r\n)可以保存,例如:{/ p>

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

我必须说我认为Bobby's answer更好,因为[:cntrl:]更能传达代码所做的事情而不是[\x00-\x1F\x7F]

警告: ereg_replace在PHP&gt; = 5.3.0中已弃用,已在PHP&gt; = 7.0.0!中删除,请使用preg_replace代替{{ 1}}:

ereg_replace

答案 1 :(得分:33)

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

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

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

答案 2 :(得分:19)

PHP支持POSIX-Classes,因此您可以使用[:cntrl:]而不是某些奇特的角色魔法:

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

修改

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

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

答案 3 :(得分:5)

要保留控制字符但使它们与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)。” )

答案 4 :(得分:1)

TLDR 答案

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

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

像这样...

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

TLDR 说明

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

工作演示

简单演示:IDEOne Demo

$text = "\u{0019}hello";
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 .NETJavaScriptPythonJavaPHPRubyPerl 中使用这些正则表达式、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没有这个功能,所以我们需要使用{{ 1}} 在正则表达式中进行手动否定。

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

所有可匹配的 Unicode 字符集

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

  • ^\PC\PL:来自任何语言的任何类型的字母。
    • \PLetter\PLl:带有大写变体的小写字母。
    • \PLowercase_Letter\PLu:带有小写变体的大写字母。
    • \PUppercase_Letter\PLt:出现在单词开头的字母,只有单词的第一个字母大写。
    • \PTitlecase_Letter\PL&:存在大小写变体的字母(Ll、Lu 和 Lt 的组合)。
    • \PCased_Letter\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:行分隔符 U+2028。
    • \PLine_Separator\PZp:段落分隔符 U+2029。
  • \PParagraph_Separator\PS:数学符号、货币符号、丁字格、方框字符等。
    • \PSymbol\PSm:任何数学符号。
    • \PMath_Symbol\PSc:任何货币符号。
    • \PCurrency_Symbol\PSk:组合字符(标记)单独作为一个完整字符。
    • \PModifier_Symbol\PSo:不是数学符号、货币符号或组合字符的各种符号。
  • \POther_Symbol\PN:任何脚本中的任何类型的数字字符。
    • \PNumber\PNd:除表意文字外的任何文字中的数字零到九。
    • \PDecimal_Digit_Number\PNl:看起来像字母的数字,例如罗马数字。
    • \PLetter_Number\PNo:上标或下标数字,或非数字 0–9 的数字(表意文字中的数字除外)。
  • \POther_Number\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:ASCII 或 Latin-1 控制字符:0x00–0x1F 和 0x7F–0x9F。
    • \PControl\PCf:不可见的格式指示符。
    • \PFormat\PCo:保留供私人使用的任何代码点。
    • \PPrivate_Use\PCs:UTF-16 编码的代理对的一半。
    • \PSurrogate\PCn:任何未分配字符的代码点。

答案 5 :(得分:-1)

正则表达式免费方法

如果你只是把我熟悉的控制字符(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);