【问题标题】:In PHP, how would I split a string where the start and end delimiter are dissimilar在PHP中,我将如何拆分开始和结束分隔符不同的字符串
【发布时间】:2014-06-15 19:53:58
【问题描述】:

简介

在 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 字符,除了 [ ]

可能有帮助的来源

Explode string except where surrounded by parentheses?


先感谢您! 我知道这是一项艰巨的任务,但我自己完全不知道该怎么做。

【问题讨论】:

  • 在这种情况下只需要学习如何使用正则表达式,没有更多的东西。这是一些extremely useful information regarding lookahead and lookbehinds的链接
  • @EugenRieck 我在这里读到preg_split() 不知道引号中的内容。
  • 你可能真的需要一个解析器。 google.ie/…
  • 我喜欢模块化正则表达式,here 是您可以与preg_split() 一起使用的解决方案。很抱歉没有解释,太忙了:)
  • @HamZa 这是一个很好的解决方案。 :)

标签: php regex string explode


【解决方案1】:

包含所有关于使用正则表达式解析 html 的免责声明...而且只有当您准备好接受一些递归之美...

匹配你想要的与分割你不想要的

如果您打算使用正则表达式(在这种情况下)来获取您的数组,那么匹配您想要的比拆分您不想要的更容易。这是一个起点,我们可以细化:

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

见demo。

工作原理:

  • 我们匹配几种可能性,由交替运算符 | 分隔
  • 第一个匹配选项(\[(?:[^[\]]++|(?1))*\])递归匹配所有[sets of [brackets]]
  • &lt;[^&gt;]*&gt; 匹配 `'
  • '[^']*' 匹配 'complete quotes'。如果需要,可以改进它以解决潜在的转义引号\'
  • [!-~]+ 匹配任何剩余的非空格可打印字符。这是一个猜测,基于您输入的唯一单词 asqwedasd,也可以改进。例如,如果出于验证目的,您想指定剩余字符串没有 &lt;&gt;[] 字符,则可以改用它(@CasimiretHippolyte 建议)\s*\K[^[&lt;]+(?&lt;!\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 正则表达式重构技术。为了使正则表达式易于理解,他将其分解为更小的命名模式:singlequotes、brackets 等等。这让他可以为所有这些组定义另一个名称: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)
|
[ ]+

【讨论】:

  • @Downvoter,想解释一下对这个工作答案的反对意见吗?
  • @Locercus why wouldn't preg_split work? 有时,拆分更容易匹配,有时匹配更容易拆分。它们是看待同一事物的两种方式。想象一下这个顺序:白、黑、白、黑……你想要所有的白人。您可以在黑色上分割,也可以与白色相匹配。
  • 我没有投反对票,但这家伙不需要解析器而不是正则表达式吗?
  • @TobyAllen 是的,我走得太快了,忘了第一行With all the disclaimers about using regex to parse html... :) 谢谢!
  • @Locercus 如果您还有其他问题,请不要犹豫。 :)
【解决方案2】:

更新:
这种模式也适用于我
(\[(?:[^\[\]]*?|(?R))*\])|(&lt;.*?&gt;)|\G\s([^&lt;&gt;\[\]]+)
Demo

【讨论】:

  • 感谢您添加demo。 [a sadasd] [ 不平衡,我是不是误会了什么?
  • 你说得对,更新了我的模式,递归有问题,现在可以工作了。
  • 顺便说一句,懒惰的? 在[^\[\]]*? 中似乎没有做任何事情,IMO 你最好使用+ 使其成为原子。
猜你喜欢
  • 2018-11-11
  • 1970-01-01
  • 2018-11-14
  • 1970-01-01
  • 1970-01-01
  • 2020-10-19
  • 2014-02-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多