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

mie*_*mia 2 php regex string explode

介绍

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

<As's\\as'dsd> asqwedasd <sa sdasd> [a sadasd] [<asdsad> [as ddsd]] 'asdsad assd'
Run Code Online (Sandbox Code Playgroud)

进入这个?

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'"
}
Run Code Online (Sandbox Code Playgroud)

更详细的解释

现在我不是最好的解释,所以我希望上面的例子很好地解释了我的情况,你不需要我的解释,但无论如何它在这里:

我希望除了一些特定的空格之外,将每个空格拆分此字符串:

  • 如果空间位于尖括号或方括号内,则不应该分割该行.见2和3.
  • 支架内可能有支架.这应该只作为一个整个字符串返回.见4号.
  • 可能存在不在括号中的项目.见号1.
  • 未包含在括号中的项目将不包含空格,除非由撇号引用.见5号.
  • 这些项目可以包含除[] <>之外的所有UTF-8字符

可能有帮助的消息来源

爆炸字符串除了用括号括起来的地方?


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

zx8*_*x81 5

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

匹配你想要什么与分裂你不想要的东西

如果您要使用正则表达式,在这种情况下,为了获得您的阵列,匹配您想要的内容将比分割您不想要的内容更容易.这是一个起点,我们可以改进:

(\[(?:[^[\]]++|(?1))*\])|<[^>]*>|'[^']*'|[!-~]+
Run Code Online (Sandbox Code Playgroud)

演示.

这个怎么运作:

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

示例代码

请参阅此演示的此输出.该数组$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]);
Run Code Online (Sandbox Code Playgroud)

另一种方案

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

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

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

这是它的要点.

这是演示.

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

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

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

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

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

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

(?&skippable)(*SKIP)(*FAIL)
|
[ ]+
Run Code Online (Sandbox Code Playgroud)