正则表达式:带分隔线模式的多行

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。

要获得 titlesubtitle 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)(?!=+))+)。您应该将最后一部分分组。