在PHP中,我如何分割开始和结束分隔符不同的字符串

时间:2014-06-15 19:53:58

标签: php regex string explode

简介

在PHP中,如何使用以下语法拆分行:

<As's\\as'dsd> asqwedasd <sa sdasd> [a sadasd] [<asdsad> [as ddsd]] 'asdsad assd'

进入这个?

array(5) {
  [0]=>
  string(14) "<As's\\as'dsd>"
  [1]=>
  string(9) "asqwedasd"
  [2]=>
  string(10) "<sa sdasd>"
  [3]=>
  string(10) "[a sadasd]"
  [4]=>
  string(20) "[<asdsad> [as ddsd]]"
  [5]=>
  string(13) "'asdsad assd'"
}

更详细的解释

现在我不是最擅长解释的,所以我希望上面的例子能够很好地解释我的情况,以至于你不需要我的解释,但无论如何它仍然存在:

我希望除了一些特定的空格之外,每个空格都要分割这个字符串:

  • 如果空间位于尖括号或方括号内,则应该 不分裂那条线。见第2和第3。
  • 支架内可能有一个支架。这应该 只是作为整个字符串返回。见第4号。
  • 可能存在不在括号中的项目。见第1号。
  • 未包含在括号中的项目不包含空格,除非由撇号引用。看到 5号。
  • 项目可以包含所有UTF-8字符,除了[]&lt; &GT;

可能有帮助的来源

Explode string except where surrounded by parentheses?


先感谢您! 我知道这是一项艰巨的任务,但我完全不知道如何做到这一点。

2 个答案:

答案 0 :(得分:5)

所有关于使用正则表达式来解析HTML的免责声明......并且只有当你准备好了一些递归之美 ...

匹配你想要的东西与你想要的东西分裂

如果你打算使用正则表达式,在这种情况下,要获得你的数组,匹配你想要的东西比分割你不想要的东西更容易。这是一个起点,我们可以改进:

(\[(?:[^[\]]++|(?1))*\])|<[^>]*>|'[^']*'|[!-~]+

请参阅demo

工作原理:

  • 我们匹配多种可能性,由交替运算符|
  • 分隔
  • 第一个匹配选项(\[(?:[^[\]]++|(?1))*\])以递归方式匹配所有[sets of [brackets]]
  • <[^>]*>匹配`'
  • '[^']*'匹配'complete quotes'。如果需要,可以对其进行改进,以考虑潜在的转义引用\'
  • [!-~]+匹配任何剩余的非空格可打印字符。这是一个猜测,基于输入中的单词asqwedasd,也可以进行细化。例如,如果要为了验证目的而指定剩余字符串没有<>[]个字符,则可以使用此字符(由@CasimiretHippolyte建议)\s*\K[^[<]+(?<!\s)

示例代码

请参阅this demo的此输出。数组$m[0]包含您想要的“拆分”。

$regex = "%(\[(?:[^[\]]++|(?1))*\])|<[^>]*>|'[^']*'|[!-~]+%";
$string = "<As's\\as'dsd> asqwedasd <sa sdasd> [a sadasd] [<asdsad> [as ddsd]] 'asdsad assd'";
$count = preg_match_all($regex,$string,$m);
print_r($m[0]);

另一种解决方案

@HamZa想出了另一个我觉得很漂亮的解决方案。他不想自己发布,但很高兴我把它添加到这里完成。

它是如何工作的?我们的想法是匹配正确的空格字符,并将它们分开。关于"regex-matching a pattern unless..."的问题详细解释了这一基本原则。首先,以与我的正则表达式类似的方式(但有更多的检查和递归),他定义了我们想要匹配的所有组,并匹配它们。然后,如果这些组匹配,则使用(*SKIP)(*F)使正则表达式失败,之后引擎将跳转到匹配的最后一个字符后面的字符串中的位置。在交替的另一边,他匹配我们将分割的空格字符,我们知道这些是正确的空格字符,因为它们与左边的表达不匹配。在此阶段,我们可以使用preg_split

进一步的改进是使用我所谓的HRRT,它代表HamZa Regex Refactoring Technique。为了使正则表达式易于消化,他将其分解为较小的命名模式:singlequotesbrackets等等。这使他可以为所有这些组定义另一个名称skippable。在定义之后,匹配开始。如果我们可以匹配skippable模式,则正则表达式会失败并显示(*SKIP)(*F),并且引擎将跳转到字符串中的下一个位置。

这就是它的要点。

这是the demo

(?(DEFINE)
   (?P<signs>
      <
         (?:
            [^<>]
            |
            (?&signs)
         )*
      >
   )

   (?P<brackets>
      \[
         (?:
            [^][]
            |
            (?&brackets)
         )*
      \]
   )

   (?P<singlequotes>
      (?<!\\)'(?:[^\\]|\\.)*?'
   )

   (?P<doublequotes>
      (?<!\\)"(?:[^\\]|\\.)*?"
   )

   (?P<quotes>
      (?&singlequotes)|(?&doublequotes)
   )

   (?P<skippable>
      (?&brackets)|(?&signs)|(?&quotes)
   )
)

(?&skippable)(*SKIP)(*FAIL)
|
[ ]+

答案 1 :(得分:3)

更新:
这种模式对我来说也很有用 (\[(?:[^\[\]]*?|(?R))*\])|(<.*?>)|\G\s([^<>\[\]]+)
Demo