正则表达式 (PHP) 删除除引号(“”和 '')之间的所有水平空格(包括转义引号)

Regex (PHP) Remove all horizontal whitespace except between quotes ("" and '') (include escaped quotes)

使用 preg_replace (PHP) 我想删除所有水平空格,引号("" 和 '')之间的空格除外(包括转义引号)

一个例子(正则表达式应该在右边转左边):

2 + 2                    => 2+2
f( " ")                  => f(" ")
f("Test \"mystring\" .") => f("Test \"mystring\" .")
f("' ",   " ")           => f("' "," ")

使用 another post 我想出了: \h(?=[^']*(?:'[^']*'[^']*)*$)(?=[^"]*(?:"[^"]*"[^"]*)*$)

这基本上是向前看并检查直到字符串末尾("" 和 '')是否有偶数个引号。

但是,我遇到转义字符和引号内引号的问题。

" ' test "  => The ' causes problem
" \" test " => The \" causes problem

我想过使用负向回顾:(?<!\)" 但无法实现。下一个正则表达式失败。当字符串包含转义引号时不匹配。

\h(?=[^"]*(?:(?<!\)"(?:[^"]*?(?<!\)")[^"]*?)*$)

您可以使用

'~(?<!\\)(?:\\{2})*(?:"[^\\"]*(?:\\.[^"\\]*)*"|\'[^\'\\]*(?:\\.[^\'\\]*)*\')(*SKIP)(*F)|\h+~s'

regex demo

详情

  • (?<!\)(?:\{2})*(?:"[^\"]*(?:\.[^"\]*)*"|'[^\']*(?:\.[^'\]*)*')(*SKIP)(*F) - '...'"...." 子字符串,其中第一个引号本身未转义,一旦匹配就会跳过(因此,其中的任何内容都不会被删除)
    • (?<!\) - 不允许 \ 字符立即出现在当前位置的左侧
    • (?:\{2})* - 双反斜杠重复零次或多次
    • (?:"[^\"]*(?:\.[^"\]*)*"|'[^\']*(?:\.[^'\]*)*') - 两种选择之一:
      • "[^\"]*(?:\.[^"\]*)*" - 双引号内的字符串文字
      • " - 双引号
      • [^\"]* - \"
      • 以外的 0 个或更多字符
      • (?:\.[^"\]*)*" - \ 的零次或多次重复,后跟任何字符 (\.),然后是 " 和 [= 以外的任何 0 个或多个字符17=] ([^"\]*)
      • | - 或
      • '[^\']*(?:\.[^'\]*)*' - 单引号内的字符串文字
    • (*SKIP)(*F) - PCRE 动词省略找到的匹配项并使正则表达式引擎继续搜索从当前正则表达式索引开始的下一个匹配项
  • |\h+ - 或 1 个或多个水平空格

PHP demo:

$strs = ['2 + 2', 'f( " ")', 'f("Test \"mystring\" .")', 'f("\' ",   " ")'];
$rx = '~(?<!\\)(?:\\{2})*(?:"[^\\"]*(?:\\.[^"\\]*)*"|\'[^\'\\]*(?:\\.[^\'\\]*)*\')(*SKIP)(*F)|\h+~s';
print_r( preg_replace($rx, '', $strs) );

输出:

Array
(
    [0] => 2+2
    [1] => f(" ")
    [2] => f("Test \"mystring\" .")
    [3] => f("' "," ")
)