Если вам нужно выполнить точные escape-последовательности, как это делает PHP, вам нужна длинная версия, то есть класс DoubleQuoted
.Я немного расширил входную строку, чтобы охватить больше escape-последовательностей, чем в вашем вопросе, чтобы сделать это более универсальным:
$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.
Однако, если вы можете прийтиблизко к этому есть функция 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";
Вывод:
\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.
Как видите, stripcslashes
отбрасывает некоторые символы здесь по сравнению с нативным выводом PHP.
( Edit: Смотрите также мой другой ответ, который предлагает что-то простое и сладкое с cstripslashes
и preg_replace
.)
Если stripcslashes
не подходит, есть DoubleQuoted
.Его конструктор принимает строку, которая обрабатывается как строка в двойных кавычках (минус замена переменных, только escape-последовательности символов).
Как указано в руководстве, существует несколько escape-последовательностей.Они выглядят как регулярные выражения, и все начинаются с \
, поэтому похоже, что на самом деле для их замены используются регулярные выражения.
Однако есть одно исключение: \\
пропустит escape-последовательность.Регулярное выражение должно иметь обратный путь и / или атомарные группы, чтобы справиться с этим, и я не бегу с ними, поэтому я просто выполнил простой трюк: я применил регулярные выражения только к тем частям строки, которые не содержат \\
, просто взорвав сначала строку, а затем снова ее применив.
Две функции замены на основе регулярных выражений, preg_replace
Doc и preg_replace_callback
Doc позволяют также работать с массивами, что довольно легко сделать.
Это делается в__toString()
Документ Функция:
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);
}
...
См. explode
Документ и implode
Док звонков.Они позаботятся о том, чтобы 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));
}
};
}
Вам нужна дополнительная информация, чтобы понять это, поскольку это еще не полный класс.Я прохожу пропущенные точки и добавляю недостающий код:
Все шаблоны, которые «ищет» класс, содержат подгруппы, по крайней мере, одну.Он входит в $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
);
* getPatterns()
функция просто упаковывает эти определения в правильные регулярные выражения 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
, которая используется для хранения, если исключение было сгенерировано, так как __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
, что приведет к перехватываемому исключению.Функция получения делает внутреннее исключение доступным, тогда:
private $exception;
...
public function getException()
{
return $this->exception;
}
Поскольку также неплохо получить доступ к исходной строке, вы можете добавить еще один метод получения для получения этого:
public function getString()
{
return $this->string;
}
И этовесь класс.Надеюсь, что это полезно.