原始:
为了简单起见,这就是我想要完成的:
源语言:
[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+ 乘以除[
和]
之外的任何字符
)
关闭 展望
正则表达式演示