正则表达式,用于拆分字符串但忽略带引号的分隔符

regexp that splits a string but ignores a quoted delimiter

提问人:Chap 提问时间:6/1/2017 更新时间:6/8/2017 访问量:84

问:

我正在编写一个 Perl 程序,它需要解析用 Wiki 标记语言编写的表。表语法使用竖线字符“|”来分隔列。

| row 1 cell 1    |row 1 cell 2  | row 1 cell 3|
| row 2 cell 1    | row 2 cell 2 |row 2 cell 3|

一个单元格可以包含零个或多个超链接,其语法如下所示:

[[wiki:path:to:page|Page Title]]   or
[[wiki:path:to:page]]

请注意,超链接可能包含竖线字符。然而,在这里,它被 [[..]] 括号“引用”。

超链接语法不能嵌套。

为了匹配和捕获每个表格行中的第一个单元格,

| Potatoes [[path:to:potatoes]]           | Daisies           |
| Kiki fruit [[path:to:kiwi|Kiwi Fruit]]  |             Lemons|

我试过了:

qr{\|                      # match literal pipe
    (.*?                   # non-greedy zero or more chars
        (?:\[\[.*?\]\])    # a hyperlink 
     .*?)                  # non-greedy zero or more chars
   \|}x                    # match terminating pipe

它起作用了,1 美元包含单元格内容。

然后,匹配

| Potatoes            | Daisies           |

我尝试将超链接设为可选:

qr{\|                      # match literal pipe
    (.*?                   # non-greedy zero or more chars
        (?:\[\[.*?\]\])?   # <-- OPTIONAL hyperlink 
     .*?)                  # non-greedy zero or more chars
   \|}x                    # match terminating pipe

这有效,但是在解析时

| Kiki fruit [[path:to:kiwi|Kiwi Fruit]]  |             Lemons|

我只得到了

 Kiki fruit [[path:to:kiwi

因此,很明显,在给定选项的情况下,它决定忽略超链接模式,并将嵌入的管道视为列分隔符。

在这里,我被困住了。而且我仍然没有处理超链接在单元格中多次出现的可能性,或者将尾随管道送回作为下一次迭代的前导管道的可能性。

没有必要在 Perl 的函数中使用正则表达式——如果更容易的话,我可以自己编写拆分循环。我看到许多类似的问题被问到,但似乎没有一个足够密切地处理这个问题。split

Regex Perl 分隔符 报价

评论

0赞 Borodin 6/1/2017
因此,您的问题是,一旦您在管道字符上拆分了文本,如果内容可能包含重命名的链接、链接或无链接,则无法解析内容。是吗?
0赞 Chap 6/1/2017
不可以,如果文本(表格整行的标记)包含重命名的链接,则无法将其拆分为列。

答:

1赞 Tanktalus 6/1/2017 #1
$ perl -MRegexp::Common -E '$_=shift; while (
  /\| # beginning pipe, and consume it
  (   # capture 1
    (?:  # inside the pipe we will do one of these:
      $RE{balanced}{-begin=>"[["}{-end=>"]]"} # something with balanced [[..]]
      |[^|] # or a character that is not a pipe
    )* # as many of those as necessary
  ) # end capture one
  (?=\|) # needs to go to the next pipe, but do not consume it so g works
  /xg
) { say $1 }' '| Kiki fruit [[path:to:kiwi|Kiwi Fruit]]  |             Lemons|'
 Kiki fruit [[path:to:kiwi|Kiwi Fruit]]  
             Lemons

这似乎可以提取您正在寻找的那些。但是,我怀疑您最好为这种语言使用适当的解析器。如果 cpan 上没有东西,我会感到惊讶,但即使没有,为此编写一个解析器可能仍然会更好,尤其是当您开始在需要处理的表中获得更多奇怪的东西时。

评论

0赞 Chap 6/2/2017
如下所述,我在 CPAN 或更高版本中找不到 Perl 解决方案。
0赞 Chap 6/3/2017
此答案还处理没有链接的单元格以及具有多个链接的单元格。对我来说,关键要点是 (1) 使用 Regexp::Common,以及 (2) 将单个非管道字符和平衡表达式视为出现零次或多次的“原子”替代方案。简单。