提问人:Chap 提问时间:6/1/2017 更新时间:6/8/2017 访问量:84
正则表达式,用于拆分字符串但忽略带引号的分隔符
regexp that splits a string but ignores a quoted delimiter
问:
我正在编写一个 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
答:
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) 将单个非管道字符和平衡表达式视为出现零次或多次的“原子”替代方案。简单。
评论