Как я мог преобразовать что-то вроде этого:
"hi (text here) and (other text)" come (again)
К этому:
"hi \(text here\) and \(other text\)" come (again)
В принципе, я хочу избежать «только» круглых скобок, находящихся внутри кавычек.
РЕДАКТИРОВАТЬ
Я к новому в Regex, и поэтому я пробовал это:
$params = preg_replace('/(\'[^\(]*)[\(]+/', '$1\\\($2', $string);
Но это будет просто избежать первого появления (.
EDIT 2
Может быть, я должен упомянуть, что моя строка может иметь эти скобки уже сбежала, и в этом случае я не хочу ускользать от них снова.
Кстати, мне нужно, чтобы он работал как для двойных, так и для одиночных кавычек, но я думаю, что могу это сделать, пока у меня есть рабочий пример для одного из них.
Это должно сделать это как для одиночных, так и для двойных кавычек:
$str = '"hi \(text here)" and (other text) come \'(again)\''; $str = preg_replace_callback('`("|\').*?\1`', function ($matches) { return preg_replace('`(?<!\\\)[()]`', '\\\$0', $matches[0]); }, $str); echo $str;
вывод
"hi \(text here\)" and (other text) come '\(again\)'
Это для PHP> = 5.3. Если у вас более низкая версия (> = 5), вы должны заменить анонимную функцию в обратном вызове отдельной функцией.
Вы можете использовать preg_replace_callback для этого;
// outputs: hi \(text here\) and \(other text\) come (again) print preg_replace_callback('~"(.*?)"~', function($m) { return '"'. preg_replace('~([\(\)])~', '\\\$1', $m[1]) .'"'; }, '"hi (text here) and (other text)" come (again)');
Как насчет уже сбежавших строк;
// outputs: hi \(text here\) and \(other text\) come (again) print preg_replace_callback('~"(.*?)"~', function($m) { return '"'. preg_replace('~(?:\\\?)([\(\)])~', '\\\$1', $m[1]) .'"'; }, '"hi \(text here\) and (other text)" come (again)');
Учитывая строку
$str = '"hi (text here) and (other text)" come (again) "maybe (to)morrow?" (yes)';
Итерационный метод
for ($i=$q=0,$res='' ; $i<strlen($str) ; $i++) { if ($str[$i] == '"') $q ^= 1; elseif ($q && ($str[$i]=='(' || $str[$i]==')')) $res .= '\\'; $res .= $str[$i]; } echo "$res\n";
Но если вы поклонник рекурсии
function rec($i, $n, $q) { global $str; if ($i >= $n) return ''; $c = $str[$i]; if ($c == '"') $q ^= 1; elseif ($q && ($c == '(' || $c == ')')) $c = '\\' . $c; return $c . rec($i+1, $n, $q); } echo rec(0, strlen($str), 0) . "\n";
Результат:
"hi \(text here\) and \(other text\)" come (again) "maybe \(to\)morrow?" (yes)
Вот как вы можете сделать это с помощью функции preg_replace_callback()
.
$str = '"hi (text here) and (other text)" come (again)'; $escaped = preg_replace_callback('~(["\']).*?\1~','normalizeParens',$str); // my original suggestion was '~(?<=").*?(?=")~' and I had to change it // due to your 2nd edit in your question. But there's still a chance that // both single and double quotes might exist in your string. function normalizeParens($m) { return preg_replace('~(?<!\\\)[()]~','\\\$0',$m[0]); // replace parens without preceding backshashes } var_dump($str); var_dump($escaped);