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

有这样的字符串:</ p>

  $ str =“  dateto:'2015-10-07 15:05'xxxx datefrom:'2015-10-09 15:05'yyyy asdf“
</ code> </ pre>

所需的结果是: </ p>

  [0] =&gt; 数组(
[0] =&gt; dateto:'2015-10-07 15:05'
[1] =&gt; xxxx
[2] =&gt; datefrom:'2015-10-09 15:05 '
[3] =&gt; yyyy
[4] =&gt; asdf

</ code> </ pre>

我得到的东西:</ p>

 <代码> preg_match_all(“/ \ '(?:?[^()] |(R))+ \' | '[^'] *'| [^(),\ S] + /  “,$ str,$ m); 
</ code> </ pre>

是:</ p>

  [0] =&gt; 数组(
[0] =&gt; dateto:'2015-10-07
[1] =&gt; 15:05'
[2] =&gt; xxxx
[3] =&gt; datefrom:' 2015-10-09
[4] =&gt; 15:05'
[5] =&gt; yyyy
[6] =&gt; asdf

</ code> </ pre>

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

展开原文

原文

having a string like this:

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

the desired result is:

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

what I get with:

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

is:

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

Also tried with preg_split("/[\s]+/", $str) but no clue how to escape if value is between quotes. Can anyone show me how and also please explain the regex. Thank you!

3个回答



通常,当您要分割字符串时,使用 preg_split </ code>并不是最佳方法( 似乎有点反直觉,但大部分时间都是这样。 一种更有效的方法是使用描述所有不是分隔符的模式(这里是空格)来查找所有项目(使用 preg_match_all </ code>):</ p>

 < 代码> $ pattern =&lt;&lt;&lt;'EOD'
~(?= \ S)[^'“\ s] (?:'[^'] *'[^'”\ s] * | “[^”] *“[^'”\ s] *)
EOD;

if(preg_match_all($ pattern,$ str,$ m))
$ result = $ m [0]; \ n </ code> </ pre>

模式细节:</ p>

 〜#pattern delimiter 

(?= \ S)#eardhead 如果在当前位置存在非
#空格字符,则断言只会成功。
#(此前瞻有用有两个原因:
# - 它允许正则表达式引擎快速找到
的开头 #下一个项目,无需在字符串
#中的每个位置测试
#的每个分支,直到一个成功。
# - 它确保了 在那里至少有一个非白色空间。
#没有它,模式可能匹配一个空字符串。
#)

[^'“\ s] *#”'#所有不是 引号或空格

(?:#finalual quoted parts
'[^'] '[^'“\ s] *#”#single quotes
|
“[^”] * “[^'”\ s] * #double quotes

~
</ code> </ pre>

演示 </ p>

请注意,使用这个有点长的模式,只需60步即可找到示例字符串的五个项目。 你也可以使用这个更短/更简单的模式:</ p>

 〜(?:[^'“\ s] + |'[^'] *'|”[^“  ] *)+〜
</ code> </ pre>

但效率稍差。</ p>
</ div>

展开原文

原文

Often, when you are looking to split a string, using preg_split isn't the best approach (that seems a little counter intuitive, but that's true most of the time). A more efficient way consists to find all items (with preg_match_all) using a pattern that describes all that is not the delimiter (white-spaces here):

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

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

pattern details:

~                    # 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
)*
~

demo

Note that with this a little long pattern, the five items of your example string are found in only 60 steps. You can use this shorter/more simple pattern too:

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

but it's a little less efficient.

dongping1689
dongping1689 关于我如何编写一般模式的知识,实践和测试。 例如,像(?:[^'\ s] + |'[^'] *')* +这样的模式如果你“展开”它会更有效,就像这样:[^'\ s] *(?:' [^'] *'[^'\ s] *)* +,您可以在Friedl书中找到此信息,但您也可以使用regex101或regexbuddy查看它,以显示所需的步骤数。 但即使有知识和食谱,你总是需要进行实验,特别是你必须要知道你的敌人:字符串。
接近 5 年之前 回复
douqiaolong0528
douqiaolong0528 这更符合经验法则,但背后的想法相对简单:1)当分隔符必须考虑到这种环境时,模式会变得很复杂且效率低下(特别是如果您需要检查之前的字符是什么,或者如果您 需要检查字符串直到结束前瞻性)。 2)有时通过否定来定义某些东西更容易。
接近 5 年之前 回复
douchunji1885
douchunji1885 谢谢你这个详细的答案! 我想知道更多的事情:“但大部分时间都是如此”是否有经验法则或某些链接我可以阅读何时/为何使用哪一个? 你是怎么写REGEX的? 你有一个工具来做到这一点,或者你知道正则表达式规则并写下来? 如果只是写下来:你是如何学习正则表达式规则的?
接近 5 年之前 回复



我会使用PCRE动词(* SKIP)(* F)</ code>,</ p>
\ n

  preg_split(“〜'[^'] '( SKIP)(* F)| \ s +〜”,$ str); 
</ code> </ pre>

DEMO </ p>
</ div>

展开原文

原文

I would use PCRE verb (*SKIP)(*F),

preg_split("~'[^']*'(*SKIP)(*F)|\s+~", $str);

DEMO

dongxing2015
dongxing2015 '[^'] *'匹配所有单引号块,以下​​(* SKIP)(* F)使匹配失败。 以下| \ s +匹配所有剩余的空格。
接近 5 年之前 回复
douaikuai2715
douaikuai2715 谢谢! 你介意解释“〜'[^'] *'(* SKIP)(* F)| \ s +〜”我只是理解它的一部分而且我想得到它
接近 5 年之前 回复



对于您的示例,您可以使用 preg_split 负面观察 < 代码>(?&lt;!\ d)</ code>,即:</ p>

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


输出:</ p>

  Array 
(\ n [0] =&gt; dateto:'2015-10-07 15:05'
[1] =&gt; xxxx
[2] =&gt; datefrom:'2015-10-09 15:05'
[3] =&gt; yyyy
[4] =&gt; asdf

</ code> </ pre>


演示:</ p> \ n

http://ideone.com/EP06Nt </ p>


正则表达式说明:</ p>

 (?&lt;!\ d)(\ s)

确认无法匹配下面的正则表达式 比赛结束于th 是位置(负向后观)«(?&lt;!\ d)»
匹配单个字符“数字”«\ d»
匹配下面的正则表达式并将其匹配捕获到后向引用号1«(\ s) »
匹配单个字符“空白字符”«\ s»
</ code> </ pre>
</ div>

展开原文

原文

For your example, you can use preg_split with negative lookbehind (?<!\d), i.e.:

<?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);

Output:

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

Demo:

http://ideone.com/EP06Nt


Regex Explanation:

(?<!\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»

doujiebo9849
doujiebo9849 确实它确实!! :)我仍然想了解为什么/如何...
接近 5 年之前 回复
duange2971
duange2971 尝试使用双引号,它也有效。
接近 5 年之前 回复
dongzhan1383
dongzhan1383 谢谢! 好的“负面回顾”,但黑客是什么?'`定义? 如果dateto:“has-double-quotes”怎么能改变?
接近 5 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐