用空格和冒号分割字符串,但如果在引号内则不分割

时间:2015-10-09 14:52:53

标签: php regex preg-match preg-match-all preg-split

有这样的字符串:

$str = "dateto:'2015-10-07 15:05' xxxx datefrom:'2015-10-09 15:05' yyyy asdf"

期望的结果是:

[0] => Array (
    [0] => dateto:'2015-10-07 15:05'
    [1] => xxxx
    [2] => datefrom:'2015-10-09 15:05'
    [3] => yyyy
    [4] => asdf
)

我得到的东西:

preg_match_all("/\'(?:[^()]|(?R))+\'|'[^']*'|[^(),\s]+/", $str, $m);

是:

[0] => Array (
    [0] => dateto:'2015-10-07
    [1] => 15:05'
    [2] => xxxx
    [3] => datefrom:'2015-10-09
    [4] => 15:05'
    [5] => yyyy
    [6] => asdf
)

还尝试使用preg_split("/[\s]+/", $str),但如果值介于引号之间,则无法知道如何转义。任何人都可以告诉我如何,也请解释正则表达式。谢谢!

2 个答案:

答案 0 :(得分:1)

通常情况下,当你想要分割一个字符串时,使用createTemplateFromFile()并不是最好的方法(这似乎有点反直觉,但大部分时间都是如此)。更有效的方法是使用描述所有不是分隔符的模式(使用preg_split)查找所有项目(白色空格):

preg_match_all

模式细节:

$pattern = <<<'EOD'
~(?=\S)[^'"\s]*(?:'[^']*'[^'"\s]*|"[^"]*"[^'"\s]*)*~
EOD;

if (preg_match_all($pattern, $str, $m))
    $result = $m[0];

demo

请注意,使用这个稍长的模式,您的示例字符串的五个项目只能找到60个步骤。您也可以使用这种更短/更简单的模式:

~                    # pattern delimiter

(?=\S)               # the lookahead assertion only succeeds if there is a non-
                     # white-space character at the current position.
                     # (This lookahead is useful for two reasons:
                     #    - it allows the regex engine to quickly find the start of
                     #      the next item without to have to test each branch of the
                     #      following alternation at each position in the strings
                     #      until one succeeds.
                     #    - it ensures that there's at least one non-white-space.
                     #      Without it, the pattern may match an empty string.
                     # )

[^'"\s]*          #"'# all that is not a quote or a white-space

(?:                  # eventual quoted parts
    '[^']*' [^'"\s]*  #"# single quotes
  |
    "[^"]*" [^'"\s]*    # double quotes
)*
~

但效率稍低。

答案 1 :(得分:0)

对于您的示例,您可以将preg_splitnegative lookbehind (?<!\d)一起使用,即:

<?php
$str = "dateto:'2015-10-07 15:05' xxxx datefrom:'2015-10-09 15:05' yyyy asdf";
$matches = preg_split('/(?<!\d)(\s)/', $str);
print_r($matches);

输出:

    Array
    (
        [0] => dateto:'2015-10-07 15:05'
        [1] => xxxx
        [2] => datefrom:'2015-10-09 15:05'
        [3] => yyyy
        [4] => asdf
    )

演示:

http://ideone.com/EP06Nt

正则表达式解释:

(?<!\d)(\s)

Assert that it is impossible to match the regex below with the match ending at this position (negative lookbehind) «(?<!\d)»
   Match a single character that is a “digit” «\d»
Match the regex below and capture its match into backreference number 1 «(\s)»
   Match a single character that is a “whitespace character” «\s»