tmt*_*tmt 10 php string escaping
有一个单引号字符串:
$content = '\tThis variable is not set by me.\nCannot do anything about it.\n';
Run Code Online (Sandbox Code Playgroud)
我想inerpret /处理字符串,好像它是双引号.换句话说,我想用实际值替换所有可能的转义字符(不仅仅是tab和linefeed,如本例所示),同时考虑到反斜杠也可能被转义,因此'\n'需要被替换由'\n'.eval()很容易做我需要的但我无法使用它.
有一些简单的解决方案吗?
(我发现一个类似的线程处理单引号字符串中变量的扩展,而我在替换转义字符后.)
如果您需要像PHP那样执行完全转义序列,则需要长版本,即DoubleQuoted类.我扩展了输入字符串以覆盖比你的问题更多的转义序列,使其更通用:
$content = '\\\\t\tThis variable\\string is\x20not\40set by me.\nCannot \do anything about it.\n';
$dq = new DoubleQuoted($content);
echo $dq;
Run Code Online (Sandbox Code Playgroud)
输出:
\\t This variable\string is not set by me.
Cannot \do anything about it.
Run Code Online (Sandbox Code Playgroud)
但是,如果你可以接近,那么有一个PHP函数被调用stripcslashes,为了比较,我添加了它的结果和PHP双引号字符串:
echo stripcslashes($content), "\n";
$compare = "\\\\t\tThis variable\\string is\x20not\40set by me.\nCannot \do anything about it.\n";
echo $compare, "\n";
Run Code Online (Sandbox Code Playgroud)
输出:
\t This variablestring is not set by me.
Cannot do anything about it.
\\t This variable\string is not set by me.
Cannot \do anything about it.
Run Code Online (Sandbox Code Playgroud)
正如您所看到的stripcslashes,与PHP本机输出相比,这里删除了一些字符.
(编辑: 见我的对方回答,以及它提供了一些简单中带甜,cstripslashes和preg_replace).
如果stripcslashes不合适,有DoubleQuoted.它的构造函数接受一个字符串,它被视为双引号字符串(减去变量替换,只有字符转义序列).
如手册所示,有多个转义序列.它们看起来像正则表达式,一切都从一开始\,所以它实际上使用正则表达式来代替它们.
但是有一个例外:\\将跳过转义序列.正则表达式需要有回溯和/或原子组来处理它,我不熟悉那些,所以我只是做了一个简单的技巧:我只将正则表达式应用于字符串中那些不包含\\的部分简单地首先爆炸字符串然后再次爆炸它.
两个基于正则表达式的替换函数preg_replaceDoc和preg_replace_callbackDoc也允许在数组上运行,因此这很容易做到.
它在__toString()Doc函数中完成:
class DoubleQuoted
{
...
private $string;
public function __construct($string)
{
$this->string = $string;
}
...
public function __toString()
{
$this->exception = NULL;
$patterns = $this->getPatterns();
$callback = $this->getCallback();
$parts = explode('\\\\', $this->string);
try
{
$parts = preg_replace_callback($patterns, $callback, $parts);
}
catch(Exception $e)
{
$this->exception = $e;
return FALSE; # provoke exception
}
return implode('\\\\', $parts);
}
...
Run Code Online (Sandbox Code Playgroud)
查看explodeDoc和implodeDoc电话.那些preg_replace_callback不会对任何包含的字符串进行操作的注意事项\\.因此,替换操作已经摆脱了处理这些特殊情况的负担.这是preg_replace_callback每个模式匹配调用的回调函数.我将它包装成一个封闭装置,因此无法公开访问:
private function getCallback()
{
$map = $this->map;
return function($matches) use ($map)
{
list($full, $type, $number) = $matches += array('', NULL, NULL);
if (NULL === $type)
throw new UnexpectedValueException(sprintf('Match was %s', $full))
;
if (NULL === $number)
return isset($map[$type]) ? $map[$type] : '\\'.$type
;
switch($type)
{
case 'x': return chr(hexdec($number));
case '': return chr(octdec($number));
default:
throw new UnexpectedValueException(sprintf('Match was %s', $full));
}
};
}
Run Code Online (Sandbox Code Playgroud)
您需要一些其他信息才能理解它,因为这不是完整的类.我浏览了缺失的点并添加了缺失的代码:
"查找"类的所有模式都包含子组,至少包含一个子组.那个进入$type并且是要翻译的单个字符或者是八x进制的空字符串和十六进制数字.
可选的第二组$number不是set(NULL)或包含八进制/十六进制数.该$matches输入被归到该行刚刚命名变量:
list($full, $type, $number) = $matches += array('', NULL, NULL);
Run Code Online (Sandbox Code Playgroud)
模式在私有成员变量中作为序列预先定义:
private $sequences = array(
'(n|r|t|v|f|\\$|")', # single escape characters
'()([0-7]{1,3})', # octal
'(x)([0-9A-Fa-f]{1,2})', # hex
);
Run Code Online (Sandbox Code Playgroud)
该getPatterns()函数只是将这些定义包装到有效的PCRE正则表达式中,如:
/\\(n|r|t|v|f|\$|")/ # single escape characters
/\\()([0-7]{1,3})/ # octal
/\\(x)([0-9A-Fa-f]{1,2})/ # hex
Run Code Online (Sandbox Code Playgroud)
这很简单:
private function getPatterns()
{
foreach($this->sequences as $sequence)
$patterns[] = sprintf('/\\\\%s/', $sequence)
;
return $patterns;
}
Run Code Online (Sandbox Code Playgroud)
现在,随着模式的概述,这解释了$matches调用回调函数时包含的内容.
要了解回调的工作原理,您需要了解的另一件事是$map.这只是一个包含单个替换字符的数组:
private $map = array(
'n' => "\n",
'r' => "\r",
't' => "\t",
'v' => "\v",
'f' => "\f",
'$' => '$',
'"' => '"',
);
Run Code Online (Sandbox Code Playgroud)
这已经是全班同学了.还有另一个私有变量$this->exception用于存储是否__toString()抛出异常,因为无法抛出异常,如果在回调函数中发生异常会导致致命错误.所以它被捕获并存储到私有类变量,这里再次是代码的一部分:
...
public function __toString()
{
$this->exception = NULL;
...
try
{
$parts = preg_replace_callback($patterns, $callback, $parts);
}
catch(Exception $e)
{
$this->exception = $e;
return FALSE; # provoke exception
}
...
Run Code Online (Sandbox Code Playgroud)
如果在替换时发生异常,则存在FALSE将导致可捕获异常的函数.getter函数使内部异常可用:
private $exception;
...
public function getException()
{
return $this->exception;
}
Run Code Online (Sandbox Code Playgroud)
因为它也很好地访问原始字符串,您可以添加另一个getter来获取:
public function getString()
{
return $this->string;
}
Run Code Online (Sandbox Code Playgroud)
这就是整个班级.希望这是有帮助的.
有一种非常简单的方法可以做到这一点,基于preg_replaceDoc,并且stripcslashes都内置:
preg_replace(
'/\\\\([nrtvf\\\\$"]|[0-7]{1,3}|\x[0-9A-Fa-f]{1,2})/e',
'stripcslashes("$0")', $content
);
Run Code Online (Sandbox Code Playgroud)
只要"\\n"应该成为"\n"等,这就有效.演示.
如果您正在寻找字面上处理这些字符串,请参阅我之前的答案.
编辑:您在评论中提问:
我只是有点疑惑,这个和stripcslashes()的输出有什么区别直接[?]
差异并不总是可见,但有一个:如果没有转义序列,stripcslashes将删除\字符.在PHP字符串中,在这种情况下不会删除斜杠.一个例子"\d",d是不是特殊字符,所以PHP保留斜线:
$content = '\d';
$content; # \d
stripcslashes($content); # d
preg_replace(..., $content); # \d
Run Code Online (Sandbox Code Playgroud)
这就是为什么preg_replace在这里很有用,它只会在那些stripcslashes按预期工作的子串中应用函数:所有有效的转义序列.