正则表达式:带分隔线模式的多行
regex: multiline with separation line pattern
我有一个文件的怪物。它可以分成如下所示的块:
========
Title: title 1
optional subtitle
====
content 1
content 2
content 3
====
Title: title 2
========
content 4
content 5
content 6
那么,我们那里有两个街区,对吗?
我正在尝试像这样拆分:
(?:^=+\n)(^Title: .*\n)(^.*\n)?(?:^=+\n)((.*\n)(?!=+))+
现在,我可以看到组很好地分开了,我得到了两个组(这是在 Java 中,顺便说一下,使用 Pattern.compile
使用 Pattern.MULTILINE
)但是当我想获取 content 时,那部分是空的。它被包含为整个组的一部分(如果我调用 match.group() 没有索引,但是 group(3) 或 group(4) 无法捕获任何内容)。我在那里错过了什么?
这是一种选择:
String input = "========\nTitle: title 1\noptional subtitle\n====\ncontent 1\ncontent 2\n\ncontent 3\n\n====\nTitle: title 2\n========\ncontent 4\ncontent 5\ncontent 6";
String[] parts = input.split("(?s)=+\nTitle:.*?\n=+");
for (int i=1; i < parts.length; ++i) {
System.out.println("PART " + i + ":");
System.out.println(parts[i]);
}
这会打印:
PART 1:
content 1
content 2
content 3
PART 2:
content 4
content 5
content 6
请注意,我在进行正则表达式拆分时使用了 (?s)
标志,以确保点可以跨换行匹配(即我使用 DOT ALL 模式)。此外,我忽略了数组中的第一个空元素,这是因为文件以定界符开头。也就是说,我们只需要结果数组中的元素 2。
要获得 title
、subtitle
、 和 content
,并且不必在正则表达式中重复太多(更简单和更好的性能),我会通过匹配 header 并手动捕获内容来做到这一点。
内容可以包含任何与完整 header 不匹配的文本。
public class Section {
private final String title;
private final String subtitle;
private String content;
public Section(String title, String subtitle) {
this.title = title;
this.subtitle = subtitle;
}
public void setContent(String content) {
this.content = content;
}
public String getTitle() {
return this.title;
}
public String getSubtitle() {
return this.subtitle;
}
public String getContent() {
return this.content;
}
public static List<Section> parse(String fileContent) {
List<Section> sections = new ArrayList<>();
Section section = null;
int start = 0;
final String regex = "(?m)^=+\RTitle: (.*)\R(?:(?!=)(.*)\R)?=+\R";
for (Matcher m = Pattern.compile(regex).matcher(fileContent); m.find(); ) {
if (section != null)
section.setContent(fileContent.substring(start, m.start()).stripTrailing());
section = new Section(m.group(1), m.group(2));
sections.add(section);
start = m.end();
}
if (section != null)
section.setContent(fileContent.substring(start).stripTrailing());
return sections;
}
}
测试
String fileContent = Files.readString(Paths.get("Test.txt"));
List<Section> sections = Section.parse(fileContent);
for (Section section : sections) {
System.out.println("Title: " + section.getTitle());
if (section.getSubtitle() != null)
System.out.println("Subtitle: " + section.getSubtitle());
System.out.println(section.getContent());
System.out.println("------");
}
输出
Title: title 1
Subtitle: optional subtitle
content 1
content 2
content 3
------
Title: title 2
content 4
content 5
content 6
------
这有效 (?:^=+\n)(^Title: .*\n)(^.*\n)?(?:^=+\n)(((.*\n)(?!=+))+)
。您应该将最后一部分分组。
我有一个文件的怪物。它可以分成如下所示的块:
========
Title: title 1
optional subtitle
====
content 1
content 2
content 3
====
Title: title 2
========
content 4
content 5
content 6
那么,我们那里有两个街区,对吗?
我正在尝试像这样拆分:
(?:^=+\n)(^Title: .*\n)(^.*\n)?(?:^=+\n)((.*\n)(?!=+))+
现在,我可以看到组很好地分开了,我得到了两个组(这是在 Java 中,顺便说一下,使用 Pattern.compile
使用 Pattern.MULTILINE
)但是当我想获取 content 时,那部分是空的。它被包含为整个组的一部分(如果我调用 match.group() 没有索引,但是 group(3) 或 group(4) 无法捕获任何内容)。我在那里错过了什么?
这是一种选择:
String input = "========\nTitle: title 1\noptional subtitle\n====\ncontent 1\ncontent 2\n\ncontent 3\n\n====\nTitle: title 2\n========\ncontent 4\ncontent 5\ncontent 6";
String[] parts = input.split("(?s)=+\nTitle:.*?\n=+");
for (int i=1; i < parts.length; ++i) {
System.out.println("PART " + i + ":");
System.out.println(parts[i]);
}
这会打印:
PART 1:
content 1
content 2
content 3
PART 2:
content 4
content 5
content 6
请注意,我在进行正则表达式拆分时使用了 (?s)
标志,以确保点可以跨换行匹配(即我使用 DOT ALL 模式)。此外,我忽略了数组中的第一个空元素,这是因为文件以定界符开头。也就是说,我们只需要结果数组中的元素 2。
要获得 title
、subtitle
、 和 content
,并且不必在正则表达式中重复太多(更简单和更好的性能),我会通过匹配 header 并手动捕获内容来做到这一点。
内容可以包含任何与完整 header 不匹配的文本。
public class Section {
private final String title;
private final String subtitle;
private String content;
public Section(String title, String subtitle) {
this.title = title;
this.subtitle = subtitle;
}
public void setContent(String content) {
this.content = content;
}
public String getTitle() {
return this.title;
}
public String getSubtitle() {
return this.subtitle;
}
public String getContent() {
return this.content;
}
public static List<Section> parse(String fileContent) {
List<Section> sections = new ArrayList<>();
Section section = null;
int start = 0;
final String regex = "(?m)^=+\RTitle: (.*)\R(?:(?!=)(.*)\R)?=+\R";
for (Matcher m = Pattern.compile(regex).matcher(fileContent); m.find(); ) {
if (section != null)
section.setContent(fileContent.substring(start, m.start()).stripTrailing());
section = new Section(m.group(1), m.group(2));
sections.add(section);
start = m.end();
}
if (section != null)
section.setContent(fileContent.substring(start).stripTrailing());
return sections;
}
}
测试
String fileContent = Files.readString(Paths.get("Test.txt"));
List<Section> sections = Section.parse(fileContent);
for (Section section : sections) {
System.out.println("Title: " + section.getTitle());
if (section.getSubtitle() != null)
System.out.println("Subtitle: " + section.getSubtitle());
System.out.println(section.getContent());
System.out.println("------");
}
输出
Title: title 1
Subtitle: optional subtitle
content 1
content 2
content 3
------
Title: title 2
content 4
content 5
content 6
------
这有效 (?:^=+\n)(^Title: .*\n)(^.*\n)?(?:^=+\n)(((.*\n)(?!=+))+)
。您应该将最后一部分分组。