4

我想用一个空格替换额外的空格(连续空白字符的实例),只要这些额外的空格不在双引号或单引号中(或我可能想要包含的任何其他附件)。

我看到了一些类似的问题,但我在上面找不到对我的需求的直接回应。谢谢!

4

2 回答 2

2

您可以分几个步骤完成。考虑以下示例:

$str = 'This is    a string with  "Bunch of    extra  spaces". Leave them  "untouched  !".';

$id = 0;
$buffer = array();
$str = preg_replace_callback('|".*?"|', function($m) use (&$id, &$buffer) {
    $buffer[] = $m[0];
    return '__' . $id++;
}, $str);
$str = preg_replace('|\s+|', ' ', $str);
$str = preg_replace_callback('|__(\d+)|', function($m) use ($buffer) {
    return $buffer[$m[1]];
}, $str);

echo $str;

这将输出字符串:

This is a string with "Bunch of    extra  spaces". Leave them "untouched  !".

虽然这不是最漂亮的解决方案。

于 2012-04-09T14:42:04.903 回答
2

希望你还在寻找,或者回来检查!这似乎对我有用:

'/\s+((["\']).*?(?=\2)\2)|\s\s+/'

...并替换为 $1

编辑

此外,如果您需要允许转义引号,例如\"or \',您可以使用以下表达式:

 '/\s+((["\'])(\\\\\2|(?!\2).)*?(?=\2)\2)|\s\s+/'

如果您想添加对括号等“平衡”引号的支持(例如(){}) ,它会变得有点粘

结束编辑

如果您发现问题或想要一些解释,请告诉我!


希望最后的编辑和警告

  • 潜在问题:如果带引号的字符串从字符串变量(或文件)的开头开始,它要么不会算作带引号的字符串(并减少任何空格),要么会丢弃整个内容,使任何内容不在引号中被视为在引号中,反之亦然 -
    • 可能解决此问题的潜在更改是使用以下匹配表达式
    • /(?:^|\s+)((["\'])(\\\\\2|(?!\2).)*?(?=\2)\2)|\s\s+/
    • 这在表达式的开头替换\s+(?:^|\s+)
    • 如果字符串以引号开头,这将在变量的开头添加一个空格- 只需 trim() 或删除该空格以继续
  • 我似乎使用了“逐行”方法(如 sed,如果我没记错的话)来达到我的原始结果 - 如果您使用“整个文件”或“整个字符串”设置或方法,回车 -换行符似乎算作两个空白字符(无法想象为什么......),因此将任何换行符变成单个空格(除非它们在引号内并且使用“dot-matches-newline”,当然)
    • 这可以通过用您想要匹配的特定字符替换.和速记字符类来解决,如下所示:\s
    • /(?:^|[ \t]+)((["\'])(\\\\\2|(?!\2)[\s\S])*?(?=\2)\2)|[ \t]{2,}/
    • 这不需要 dot-matches-newline 开关,并且只用一个空格替换多个空格或制表符-而不是换行符(当然,只有当它们没有被引用时)

例子

此链接显示了在http://codepad.viper-7.com上的示例文本中使用的第一个表达式和最后一个表达式的示例

于 2012-04-09T16:31:37.453 回答