【问题标题】:How could I find all whitespaces excluding the ones between quotes?我怎样才能找到除引号之间的空格之外的所有空格?
【发布时间】:2009-11-12 12:40:35
【问题描述】:

我需要用空格分割字符串,但引号中的短语应该保持不分割。示例:

  word1 word2 "this is a phrase" word3 word4 "this is a second phrase" word5

这应该在 preg_split 之后产生数组:

array(
 [0] => 'word1',
 [1] => 'word2',
 [2] => 'this is a phrase',
 [3] => 'word3',
 [4] => 'word4',
 [5] => 'this is a second phrase',
 [6]  => 'word5'
)

我应该如何编写我的正则表达式来做到这一点?

附言。有related question,但我认为它不适用于我的情况。接受的答案提供了正则表达式来查找单词而不是空格。

【问题讨论】:

  • 根据您提供的示例,该相关问题看起来正是您想要做的。您是否尝试过接受的答案?发生了什么?
  • 是的,我试过了。我使用 php,而不是 .NET。我不能使用正则表达式结果的内联过滤。而且,正如我所说, \w+|"[\w\s]*" 对我也不起作用

标签: php regex


【解决方案1】:

在#regex irc 频道 (irc.freenode.net) 的用户 MizardX 的帮助下找到了解决方案。它甚至支持单引号。

$str= 'word1 word2 \'this is a phrase\' word3 word4 "this is a second phrase" word5 word1 word2 "this is a phrase" word3 word4 "this is a second phrase" word5';

$regexp = '/\G(?:"[^"]*"|\'[^\']*\'|[^"\'\s]+)*\K\s+/';

$arr = preg_split($regexp, $str);

print_r($arr);

结果是:

Array (
    [0] => word1
    [1] => word2
    [2] => 'this is a phrase'
    [3] => word3
    [4] => word4
    [5] => "this is a second phrase"
    [6] => word5
    [7] => word1
    [8] => word2
    [9] => "this is a phrase"
    [10] => word3
    [11] => word4
    [12] => "this is a second phrase"
    [13] => word5  
)

附言。唯一的缺点是这个正则表达式只适用于 PCRE 7。

原来我在生产服务器上没有 PCRE 7 支持,那里只安装了 PCRE 6。尽管它不如 PCRE 7 的前一个灵活,但可以工作的正则表达式是(摆脱了 \G 和 \K):

/(?:"[^"]*"|\'[^\']*\'|[^"\'\s]+)+/

对于给定的输入结果与上面相同。

【讨论】:

  • \G 和 \K 代表什么?
  • \G 将匹配锚定到前一个匹配结束的地方(粗略地说),或者如果没有前一个匹配,则锚定到输入的开头。 \K我不得不抬头:意思是“假装比赛真的从这里开始”;虽然正则表达式匹配一个标记和它后面的空格,但它的行为就像它只匹配空格一样。有点像穷人的向后看,只是在大多数情况下,它似乎比向后看要好。我想知道为什么这个功能不更常见? pcre.org/pcre.txt
  • 谢谢艾伦。在 regex.info 中都找不到...而且很难用谷歌搜索 regex。
  • 没有什么比挖掘 3 岁的问题更重要的了!很好地保持最新状态。
【解决方案2】:

假设您的引号定义明确,即成对出现,您可以每隔 2 个字段展开并遍历 for 循环。例如

$str = "word1 word2 \"this is a phrase\" word3 word4 \"this is a second phrase\" word5 word6 \"lastword\"";
print $str ."\n";
$s = explode('"',$str);
for($i=1;$i<count($s);$i+=2){
    if ( strpos($s[$i] ," ")!==FALSE) {
        print "Spaces found: $s[$i]\n";
    }
}

输出

$ php test.php
Spaces found: this is a phrase
Spaces found: this is a second phrase

不需要复杂的正则表达式。

【讨论】:

  • 当然我可以不用正则表达式来做到这一点,但这不是我的情况。
【解决方案3】:

使用您链接的其他问题中的正则表达式相当容易?

<?php

$string = 'word1 word2 "this is a phrase" word3 word4 "this is a second phrase" word5';

preg_match_all( '/(\w+|"[\w\s]*")+/' , $string , $matches );

print_r( $matches[1] );

?>

输出:

Array
(
     [0] => word1
     [1] => word2
     [2] => "this is a phrase"
     [3] => word3
     [4] => word4
     [5] => "this is a second phrase"
     [6] => word5
)

【讨论】:

  • 也应该找到的特殊字符(例如和号)呢?不仅&符号将未处理。此外,不同的符号应该以不同的方式处理。例如,如果遇到大括号,我需要将它们包含在搜索结果中。
  • @altern,我敢肯定edds 不介意你根据自己的需要调整他的例子......
【解决方案4】:

有人想对标记化和正则表达式进行基准测试吗?我的猜测是,explode() 函数对于任何速度优势来说都太重了。不过,这里有另一种方法:

(已编辑,因为我忘记了存储引用字符串的 else 情况)

$str = 'word1 word2 "this is a phrase" word3 word4 "this is a second phrase" word5';

// initialize storage array
$arr = array();
// initialize count
$count = 0;
// split on quote
$tok = strtok($str, '"');
while ($tok !== false) {
    // even operations not in quotes
    $arr = ($count % 2 == 0) ? 
                               array_merge($arr, explode(' ', trim($tok))) :
                               array_merge($arr, array(trim($tok)));
    $tok = strtok('"');
    ++$count;
}

// output results
var_dump($arr);

【讨论】:

    【解决方案5】:
    $test = 'word1 word2 "this is a phrase" word3 word4 "this is a second phrase" word5';
    preg_match_all( '/([^"\s]+)|("([^"]+)")/', $test, $matches);
    

    【讨论】:

      猜你喜欢
      • 2014-07-27
      • 2013-06-22
      • 1970-01-01
      • 2020-09-06
      • 2020-05-08
      • 1970-01-01
      • 2013-07-22
      • 2022-01-12
      • 1970-01-01
      相关资源
      最近更新 更多