提取括在方括号中的文本(方括号内的属性之间带有分隔符)



原始:

为了简单起见,这就是我想要完成的:

源语言:

[category - subcategory] [some text - more text] [2018-12-31] text title here

期望的结果:

category
subcategory
some text
more text
2018-12-31
text title here

方括号的数量始终相同,但方括号之间的封闭属性数量可能不同:

[category - subcategory] [some text - more text] [2018-12-31] text title here
[category - subcategory] [some text] [2018-12-31] text title here more text
[category] [some text - more text - even more] [2018-12-31] text title here more text

因此,前两个 [ ][ ] 中的文本将由 -

我昨天第一次尝试正则表达式,这有点令人头疼。我正在尝试做的事情可能吗?

是的,这是可能的,但相当复杂,一些表达式可能类似于:

[s*(s*d{4}s*-s*d{2}s*-s*d{2}s*)s*]|(?<=[|-)s*(.*?)s*(?=-|])|([A-Za-z].*)

我们将首先使用

[s*(s*d{4}s*-s*d{2}s*-s*d{2}s*)s*]

然后在另一个方括号中加入其他所需的子字符串,使用

(?<=[|-)s*(.*?)s*(?=-|])

最后一句是:

([A-Za-z].*)

例如。我们可以将其他字符添加到此字符类中

[A-Za-z]

如果有必要的话。

如果您希望探索/简化/修改表达式,请在此演示的右上角面板上解释该表达式。

演示

在此演示中,您可以看到捕获组的工作原理:

const regex = /[s*(s*d{4}s*-s*d{2}s*-s*d{2}s*)s*]|(?<=[|-)s*(.*?)s*(?=-|])|([A-Za-z].*)/gm;
const str = `[category - subcategory] [some text   -   more text  ] [2018-12-31] text title here
[category - subcategory] [some text] [  2018 - 12 -31  ] text title here more text
[category] [some text - more text - even more] [2018-12-31] text title here more text
[category] [some text - more text - even more - some text - more text   -   even more  ] [2018-12-31] text title here more text`;
let m;
while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}

// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`Found match, group ${groupIndex}: ${match}`);
});
}

我将通过两步过程解决此问题。

首先,使用此正则表达式提取方括号之间和之后的块:

[(.*?)]s*[(.*?)]s*[(.*?)]s*(.*)

假设输入中的其他地方不允许使用方括号,这将为您提供四个组匹配项,分别是类别、文本、日期和自由文本。

详:

  • []匹配文字方括号。
  • (.*?)以非贪婪的方式匹配方括号之间的文本,从而避免了必须使用更笨拙的字符集([^][]*)来排除它们。
  • s*允许块之间有任意数量的空格。如果模式始终只有一个空格,您也可以只使用一个空格。
  • (.*)最后只会抓住剩下的一切。

然后,您可以将"-"上的类别和文本拆分为数组或列表,以包含所需的细分。由于您希望在前两组括号中捕获可变数量的字段,因此尝试在一个大正则表达式中捕获所有字段似乎比当split()可以轻而易举地完成这项工作时更困难。

PS:由于您没有指定编程语言,因此我为您提供了描述性的伪代码; 您必须查找如何访问匹配组并用您的语言进行拆分。

演示

您还可以应用sed以获得所需格式的结果

echo [category - subcategory] [some text - more text] [2018-12-31] text title here 
| sed -e $'s/] /\n/g' -e $'s/ - /\n/g' -e 's/[//g'

输出:

category
subcategory
some text
more text
2018-12-31
text title here

首先将](space)(space)-(space)转换为新行,然后将[替换为empty

尝试模式[.+?(?(?<= - ) - |])

解释:

[- 从字面上匹配[

.+?- 匹配任意字符中的一个或多个(非贪婪)

(?(?<= - ) - |])- 条件:如果满足正外观(?<= - )(匹配-字面意思),则匹配-,否则从字面上匹配]]

在此处输入链接说明

帮自己一个忙,编写自己的解析器,例如使用Python(还没有标记语言?),这可能是parsimonious

from parsimonious.grammar import Grammar
from parsimonious.nodes import NodeVisitor
data = ["[category - subcategory] [some text - more text] [2018-12-31] text title here",
"[category - subcategory] [some text] [2018-12-31] text title here more text",
"[category] [some text - more text - even more] [2018-12-31] text title here more text",
"[category - subcategory] [some text - more text] [2018-12-31] text title here"]

class TextVisitor(NodeVisitor):
grammar = Grammar(
r"""
content = (section / text)+
section = lpar notpar (sep notpar)* rpar ws*
text    = ~"[^][]+"
lpar    = "["
rpar    = "]"
notpar  = ~"(?:(?! - )[^][])+"
sep     = " - "
ws      = ~"s+"
"""
)
def generic_visit(self, node, visited_children):
return visited_children or node
def visit_section(self, node, visited_children):
_, cat1, catn, *_ = visited_children
categories = [cat1.text] + [cat[1].text for cat in catn]
return categories
def visit_text(self, node, visited_children):
return [node.text]
def visit_content(self, node, visited_children):
result = [textnode
for child in visited_children
for subchild in child
for textnode in subchild]
return result

for datapoint in data:
tv = TextVisitor()
result = tv.parse(datapoint)
print("n".join(result))
print("###")

这会产生

category
subcategory
some text
more text
2018-12-31
text title here
###
category
subcategory
some text
2018-12-31
text title here more text
###
category
some text
more text
even more
2018-12-31
text title here more text
###
category
subcategory
some text
more text
2018-12-31
text title here
###

如果支持G锚点在上一个匹配项结束时断言位置,要获取方括号内的单独部分而不带连字符,您可以使用:

(?:[|G(?!^))([^-][s]+(?:[ -][^-][s]+)*)(?: - )?(?=[^[]]*])

比赛在第一个捕获组中。

解释

  • (?:非捕获组
    • [比赛[
    • |
    • G(?!^)在上一场比赛中而不是在开始时断言位置
  • )关闭非捕获组
  • (捕获组 1
    • [^-][s]+匹配 1+ 除-][和空格字符之外的任何字符
    • (?:[ -][^-][s]+)*重复 0+ 次与以前的模式相同,仅在前面加上空格或连字符
  • )关闭组
  • (?: - )?可选地匹配空格之间的-
  • (?=积极向前看,断言右边的东西是
    • [^[]]*]匹配 0+ 乘以除[]之外的任何字符
  • )关闭 展望

正则表达式演示

最新更新