在多行字符串中,如何匹配每行以竖线字符开头的新行序列

Within a multiline string how does one match sequences of new lines where each line starts with the pipe character

嘿,我有一个类似这样的字符串:

字符串:

foo | bar
|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar
bar

我需要一个匹配第一个“|”开始的所有内容的正则表达式在一行开始到不以“|”开头的第一行(作为一场比赛)。 所以所示示例中的匹配将是这样的:

正确匹配:

[
|foo | bar
|foo bar
|bar foo foo
,
|bar foo
|foo bar
]

我想出了这个 /\|([\s\S]+)(\n\|)/g 但它与以下内容匹配,但不正确:

不正确的匹配:

[
| bar
|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|
]

希望您能理解我的需要,感谢您的宝贵时间!

回答

按照你的问题,从第一个“|”开始匹配所有内容在第一行不以“|”开头的行开头,您可以使用此正则表达式:

/^\|([\s\S]*?)(?:(?!^[^\|])[\s\S])*/gm

需要注意 m 标志(多行)才能匹配多行字符串。

给你的示例字符串

foo | bar
|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar
bar

这将匹配

|foo | bar
|foo bar
|bar foo foo

|bar foo
|foo bar

工作原理:

^\| 匹配任何以“|”开头的行特点。然后,([\s\S]*?) 匹配 0 个或多个任何字符,包括新行“Lazily”(意味着只捕获最小值)。最后 (?:(?!^[^\|])[\s\S])* 匹配到不以“|”开头的新行 (^) ([^\|]).

这里有一个 link 到 Regexr,详细说明了它的工作原理和实际应用示例。

const str =
`foo | bar
|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar
bar`

console.log(str.match(/^\|([\s\S]*?)(?:(?!^[^\|])[\s\S])*/gm))

一种方法仅基于 match might not in any case work for the OP's requirement(s). But a working solution definitely can be achieved with both a regex based split and a sanitizing filter ...类似于 ...

`multilines`.split(/(?:^[^|].*\n)+/gm).filter(str => str !== '' && str !== '\n');

这是为什么?

由于 OP 希望保留任何以连续换行为特征的子字符串,每行都以 | 开头,因此 OP 只需要在每个不以 [=18= 开头的新行处拆分多行字符串].

因此第一个有效的正则表达式可能是 /^[^|].*\n/gm。读起来是这样的...

  • / ... /mm 多行模式下运行,从而使 ^ 能够匹配字符串中的每个新行。
  • ^[^|] 在每个新行的开头匹配一个不是竖线的字符/| ... 然后 ...
  • .*\n 匹配任何其他内容,包括最后一个换行符

此匹配项将用于 split 操作,从而将 OP 正在查找的行与应该从 OP 所需结果中排除的行分开。

由于正则表达式还不是很理想,并且由于 split 的性质,结果具有一些伪像 ...

console.log(
`foo | bar
|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar
bar`.split(/^[^|].*\n/gm)
);

console.log(
`foo | bar
|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar
bar

foo | bar
bar

|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar

bar

`.split(/^[^|].*\n/gm)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

...我们在下一次代码迭代中将其删除。

console.log(
`foo | bar
|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar
bar`.split(/(?:^[^|].*\n)+/gm)
);

console.log(
`foo | bar
|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar

bar

foo | bar
bar

|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar

bar

`.split(/(?:^[^|].*\n)+/gm)
);

console.log(
`foo | bar
|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar
bar`.split(/(?:^[^|].*\n)+/gm).filter(str => str !== '' && str !== '\n')
);

console.log(
`foo | bar
|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar

bar

foo | bar
bar

|foo | bar
|foo bar
|bar foo foo
foo bar
|bar foo
|foo bar

bar

`.split(/(?:^[^|].*\n)+/gm).filter(str => str !== '' && str !== '\n')
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

第一个正则表达式 ... /^[^|].*\n/gm ... 已改进为 /(?:^[^|].*\n)+/gm。因此,第二个版本现在匹配不需要的换行符序列(不捕获它们......(?: ...))。

结果几乎涵盖了OP的要求。但是对于边缘情况,人们仍然会在结果数组中遇到伪影。因此,为了始终处于保存状态,需要通过 filter 条件对后者进行消毒。