0

我有正则表达式:

BEGIN\s+\[([\s\S]*?)END\s+ID=(.*)\]

从下面的文本中选择多行文本和 ID。我只想选择带有 prefix 的 ID X_,但是如果我更改ID=(.*)ID=(X_.*)begin 是从第二对而不是从第三对中选择的,因为我需要。有人可以帮我正确表达吗?

文本示例:

BEGIN [
text a
END ID=X_1]

BEGIN [
text b
text c
END ID=Y_1]

text aaa
text bbb

BEGIN [
text d
text e
END ID=X_2]

text xxx

BEGIN [
text bbb
END ID=X_3]
4

3 回答 3

1

假设块内没有任何换行符并且BEGIN/END语句是其行的第一个非空格,我会这样编写正则表达式(Perl 表示法;/x如果您使用,请更改分隔符并删除注释、空格和修饰符不同的引擎)

m{
  \n \s* BEGIN \s+ \[          # match the beginning
     ( (?!\n\s*\n) .)*?        # match anything that isn't an empty line
                               # checking with a negative look-ahead (?!PATTERN)
  \n \s* END \s+ ID=X_[^\]]* \] # the ID may not contain "]"
}sx                            # /x: use extended syntax, /s: "." matches newlines

如果内容可能是任何东西,最好创建一个所有块的列表,然后对它们进行 grep。此正则表达式匹配任何块:

m{ (
  BEGIN \s+ \[
  .*?              # non-greedy matching is important here
  END \s+ ID=[^\]]* \] # greedy matching is safe here
) }xs

(如果需要,添加换行符)

然后只保留与此正则表达式匹配的匹配项:

/ID = X_[^\]]* \] $/x  # anchor at end of line

如果我们不这样做,回溯可能会阻止正确匹配[\s\S]*?可以包含END ID=X_)。您的正则表达式会将任何内容放入块中,直到看到 X_.*.

所以使用BEGIN\s+\[([/s/S]*?)END\s+ID=(.*?)\]- 注意额外的问号 - 一个匹配将是:

BEGIN [
text b
text c
END ID=Y_1]

text aaa
text bbb

BEGIN [
text d
text e
END ID=X_2]

…而不是在Y_. 贪婪匹配(您未更改的正则表达式)应该导致整个文件被匹配:您(.*)吃掉所有字符(直到文件末尾)然后返回直到找到一个].

编辑:

如果您使用 perls 正则表达式引擎,我们可以使用(*FAIL)动词:

/BEGIN\s+\[(.*?)END\s+ID=(X_[^\]]*|(*FAIL))\]/s

“要么有一个以 开头的 ID,X_要么匹配失败”。但是,这并不能解决END ID=X_1]数据中的 -like 语句的问题。

于 2012-08-03T06:30:40.897 回答
1

正如人们一直在说的那样,这并不是.*吞噬一切,而是[\s\S]*?. .*不能这样做,因为(正如 OP 所说)点与换行符不匹配。

END\s+ID=(X_.*)\]您的正则表达式的一部分无法匹配第二个块的最后一行时,您期望它放弃该块并从第三个块重新开始。这就是它必须做的最短匹配。

实际上,它会回溯到行首并让我们[\s\S]*?使用它。并且它一直在消耗直到找到一个END\s+ID=(X_.*)\]可以匹配的地方,这恰好是第三块的最后一行。

以下正则表达式通过逐行匹配来避免该问题,检查每一个以查看它是否以END. 这有效地将匹配一次限制在一个块上。

(?m)^BEGIN\s+\[[\r\n]+((?:(?!END).*[\r\n]+)*)END\s+ID=(X_.*)\]

请注意,我曾经^将每个匹配项锚定到一行的开头,所以我曾经(?m)打开多行模式。但我没有——而且你不应该——打开单行/DOTALL 模式。

于 2012-08-03T10:00:03.550 回答
0

将您更改.*[^\]]*(即匹配非] s),以便您的匹配项不会溢出 END 块,从而为您提供类似BEGIN\s+\[([^\]]*?)END\s+ID=(X_[^\]]*)\]

于 2012-08-03T06:17:59.537 回答