【问题标题】:Replace all occurences of char inside quotes on PHP替换PHP上引号内所有出现的char
【发布时间】:2013-02-04 14:07:39
【问题描述】:

我怎样才能转换这样的东西:

"hi (text here) and (other text)" come (again)

到这里:

"hi \(text here\) and \(other text\)" come (again)

基本上,我想“只”转义引号内的括号。

编辑

我是 Regex 的新手,所以我尝试了这个:

$params = preg_replace('/(\'[^\(]*)[\(]+/', '$1\\\($2', $string);

但这只会避开第一次出现的 (.

编辑 2

也许我应该提一下,我的字符串可能已经转义了这些括号,在这种情况下,我不想再次转义它们。

顺便说一句,我需要它同时适用于双引号和单引号,但我认为只要我有其中一个的工作示例,我就可以做到这一点。

【问题讨论】:

  • 我想我不明白你想将转义添加到第一个字符串吗?
  • 不,他想转义引号内的括号
  • @JohnConde 我改进了问题内容,​​以便告诉我到目前为止我尝试了什么。
  • 你对"hi (text" here) and ("other "text)"这样的情况有什么看法?

标签: php regex escaping preg-replace


【解决方案1】:

单引号和双引号都应该这样做:

$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),则必须将回调中的匿名函数替换为单独的函数。

【讨论】:

  • @CristianoSantos 是的。但如果您不希望这样,您可能需要更新您的问题。
  • @flec 您不需要在字符组内转义括号。
【解决方案2】:

您可以为此使用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)');

【讨论】:

  • 您的输出缺少引号,因为您只返回替换的子匹配项。
【解决方案3】:

给定字符串

$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)

【讨论】:

    【解决方案4】:

    下面是使用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);
    

    【讨论】:

      【解决方案5】:

      这可以在没有在正则表达式调用中嵌套正则表达式调用的情况下完成。我也不赞同带有条件和临时变量的冗长循环。

      这个任务要召唤的英雄是\G——“继续”元字符。它允许从字符串中的一个位置开始匹配,并从最后一个匹配完成的位置继续匹配。

      代码:(Demo)

      $str = '"hi (text here) and (other text)" come (again) and "(again)", right?';
      
      echo preg_replace(
               '~(?:\G(?!^)|"(?=[^"]+"))[^"()]*(?:"(*SKIP)(*FAIL)|\K[()])~',
               '\\\$0',
               $str
           );
      

      输出:

      "hi \(text here\) and \(other text\)" come (again) and "\(again\)", right?
      

      故障:(Demo)

      (?:               #start noncapturing group 1
        \G(?!^)         #continue, do not match from start of string
        |               #OR
        "(?=[^"]+")     #match double quote then lookahead for the second double quote
      )                 #end noncapturing group 1
      [^"()]*           #match zero or more characters not (, ), or "
      (?:               #start noncapturing group 2
        "(*SKIP)(*FAIL) #consume but do not replace
        |               #OR
        \K              #forget any previously matched characters
        [()]            #match an opening or closing parenthesis
      )                 #end noncapturing group 2
      

      当转义字符应被取消其在字符串/模式中的正常含义时,此解决方案不适应边缘场景。

      【讨论】:

        猜你喜欢
        • 2018-01-20
        • 1970-01-01
        • 1970-01-01
        • 2017-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-15
        相关资源
        最近更新 更多