Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/239.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 解释单引号字符串中的转义字符_Php_String_Escaping - Fatal编程技术网

Php 解释单引号字符串中的转义字符

Php 解释单引号字符串中的转义字符,php,string,escaping,Php,String,Escaping,具有单引号的字符串: $content = '\tThis variable is not set by me.\nCannot do anything about it.\n'; 我想对字符串进行预处理,就像它是双引号一样。换句话说,考虑到反斜杠也可能转义,我想用实际值替换所有可能的(不只是本例中的制表符和换行符),因此“\\n”需要替换为“\n”eval()可以轻松完成我需要的任务,但我无法使用它 有什么简单的解决方案吗? (我发现的在替换转义字符后处理单引号字符串中变量的扩展。)基于正则

具有单引号的字符串:

$content = '\tThis variable is not set by me.\nCannot do anything about it.\n';
我想对字符串进行预处理,就像它是双引号一样。换句话说,考虑到反斜杠也可能转义,我想用实际值替换所有可能的(不只是本例中的制表符和换行符),因此“\\n”需要替换为“\n”eval()可以轻松完成我需要的任务,但我无法使用它

有什么简单的解决方案吗?


(我发现的在替换转义字符后处理单引号字符串中变量的扩展。)

基于正则表达式的解决方案在这里可能最易于维护(文档中甚至提供了字符串中有效转义序列的定义作为正则表达式):

上述方面也可以(而且确实应该)改进:

  • 将替换函数打包为匿名函数
  • 可能将
    $map
    替换为
    开关
    ,以免费提高性能

如果需要像PHP那样执行精确的转义序列,则需要长版本,即
双引号的
类。我对输入字符串进行了一些扩展,以涵盖比您问题中更多的转义序列,从而使其更通用:

$content = '\\\\t\tThis variable\\string is\x20not\40set by me.\nCannot \do anything about it.\n';

$dq = new DoubleQuoted($content);

echo $dq;
输出:

\\t This variable\string is not set by me.
Cannot \do anything about it.
\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.
但是,如果您可以接近这一点,那么有一个PHP函数名为,为了比较,我添加了它的结果和PHP双引号字符串:

echo stripcslashes($content), "\n";

$compare = "\\\\t\tThis variable\\string is\x20not\40set by me.\nCannot \do anything about it.\n";

echo $compare, "\n";
输出:

\\t This variable\string is not set by me.
Cannot \do anything about it.
\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.
如您所见,与PHP本机输出相比,stripcslashes在这里删除了一些字符

编辑:它通过
cstripslashes
preg\u replace
提供了一些简单而甜蜜的东西)

如果
stripcslashes
不合适,则存在
双引号
。它的构造函数接受一个被视为双引号字符串的字符串(减去变量替换,只有字符转义序列)

如手册所述,有多个转义序列。它们看起来像正则表达式,并且都以
\
开头,所以看起来几乎可以用正则表达式来代替它们

但是有一个例外:
\\
将跳过转义序列。正则表达式需要有回溯和/或原子组来处理这个问题,而我对它们不太熟悉,所以我只做了一个简单的技巧:我只将正则表达式应用到字符串中不包含
\\
的部分,只需先分解字符串,然后再内爆它

这两个基于正则表达式的replace函数,以及,也允许对数组进行操作,因此这是非常容易做到的

它在函数中完成:

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);
    }
    ...
请参阅和电话。它们注意到,
preg\u replace\u callback
不会对任何包含
\
的字符串进行操作。因此,更换操作已从处理这些特殊情况的负担中解脱出来。这是回调函数,由
preg\u replace\u 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));
        }   
    };
}
您需要一些额外的信息来理解它,因为这还不是完整的类。我检查了缺失的点,并添加了缺失的代码:

类“查找”的所有模式都包含子组,至少一个。这一个进入
$type
,它要么是要翻译的单个字符,要么是八进制的空字符串,要么是十六进制数的
x

可选的第二组
$number
未设置(
NULL
)或包含八进制/十六进制数字。
$matches
输入标准化为此行中刚命名的变量:

list($full, $type, $number) = $matches += array('', NULL, NULL);
模式预先定义为私有成员变量中的序列:

private $sequences = array(
    '(n|r|t|v|f|\\$|")', # single escape characters
    '()([0-7]{1,3})', # octal
    '(x)([0-9A-Fa-f]{1,2})', # hex
);
函数的作用是将这些定义包装成有效的PCRE正则表达式,如:

/\\(n|r|t|v|f|\$|")/ # single escape characters
/\\()([0-7]{1,3})/ # octal
/\\(x)([0-9A-Fa-f]{1,2})/ # hex
这很简单:

private function getPatterns()
{
    foreach($this->sequences as $sequence)
        $patterns[] = sprintf('/\\\\%s/', $sequence)
        ;

    return $patterns;
}
现在,正如所概述的模式一样,这解释了调用回调函数时,
$matches
包含的内容

要了解回调如何工作,还需要了解另一件事
$map
。这只是一个包含单个替换字符的数组:

private $map = array(
    'n' => "\n",
    'r' => "\r",
    't' => "\t",
    'v' => "\v",
    'f' => "\f",
    '$' => '$',
    '"' => '"',
);
这已经差不多是全班的了。另一个私有变量
$this->exception
用于存储抛出的异常,因为
\u 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
        }
        ...
如果在替换时出现异常,则函数存在
FALSE
,这将导致可捕获的异常。getter函数使内部异常可用,然后:

private $exception;
...
public function getException()
{
    return $this->exception;
}
由于也可以访问原始字符串,因此可以添加另一个getter来获得:

public function getString()
{
    return $this->string;
}

这就是全班同学。希望这会有所帮助。

有一种非常简单的方法可以实现这一点,它基于和,两者都是内置的:

preg_replace_callback(
    '/\\\\([nrtvf\\\\$"]|[0-7]{1,3}|\x[0-9A-Fa-f]{1,2})/',
    fn($matches) => stripcslashes($matches[0]), $content
);
只要
“\\n”
应变为
“\n”
等,此功能就可以工作

如果您希望逐字处理这些字符串,请参阅我的

编辑:您在评论中询问:

我只是有点困惑,这个和stripcslashes()的直接输出有什么区别[?]

区别并不总是可见的,但有一个区别:
stripcslashes
将删除
\
chracter,如果没有后续转义序列。在PHP字符串中,在这种情况下不能删除斜杠。例如,
“\d”
d
不是特殊字符,因此PHP保留斜杠:

$content = '\d';
$content; # \d
stripcslashes($content); # d
preg_replace(..., $content); # \d
这就是为什么
preg\u replace
在这里很有用,它只会应用函数