Regex -仅当模式在特定模式之后或之前时才匹配该模式

m2xkgtsf  于 2023-05-08  发布在  其他
关注(0)|答案(2)|浏览(179)

我有一个巨大的字符串(markdown),它包含这样的内容:

表头1

{~1.0} Lorem ipsum dolor sit amet.[医][牙][牙][牙][牙][牙][牙][牙][牙][牙]联系我们
{~4.0} Lorem ipsum dolor sit amet.[医][牙][牙][牙][牙][牙][牙][牙][牙][牙]联系我们
{~7.0} Lorem ipsum dolor sit amet.[医][牙][牙][牙][牙][牙][牙][牙][牙][牙][牙][001 pdf 1st-31files]

表头2

{~10.0} Lorem ipsum dolor sit amet.[医][牙][牙][牙][牙][牙][牙][牙][牙][牙][牙][2019 - 01 - 12]
{~113.0} Lorem ipsum dolor sit amet.[医][牙][牙][牙][牙][牙][牙][牙][牙][牙][001 pdf 1st-31files]
{~16.0} Lorem ipsum dolor sit amet.[医][牙][牙][牙][牙][牙][牙][牙][牙][牙][牙][2019 - 01 - 18]

表头3

{~19.0} Lorem ipsum dolor sit amet.[医][牙][牙][牙][牙][牙][牙][牙][牙][牙][牙][2019 - 09 - 21]
{~22.0} Lorem ipsum dolor sit amet.[医][牙][牙][牙][牙][牙][牙][牙][牙][牙][牙] 2019 - 04 - 04 00:00:00
{~25.0} Lorem ipsum dolor sit amet.[医][牙][牙][牙][牙][牙][牙][牙][牙][牙][牙][2019 - 04 - 27]
这是标记{~x.x}
我将把“section”称为一个标题和一个段落的组合。
我需要匹配每个部分的第一个和最后一个标记。
目前,我正在使用JavaScript中的正则表达式/\s?{([^}]*(~\d*(?:\.\d+)?)[^}]*)}\s?/g,它是从this question的选定答案中获得的,以捕获所有标记,但现在我需要修改它,以便仅捕获每个“部分”中的第一个和最后一个标记。
字符串来自用户输入,所以我不能提前知道一个“节”将有多少段落,也不知道标题的内容,我所知道的是至少有一个节(意味着一个标题后面跟着x数量的段落)。

watbbzwu

watbbzwu1#

这是我的变体,可能比大多数其他变体少regexp:y,但它可以工作:

function getNumbers(str) {
  return `\n${str}`.split('\n## ')
    .map(x => [...x.matchAll(/\{~(\d|\.)*\}/g)].map(x => x[0]))
    .map(x => [x[0], x.slice(-1)]).flat(2).filter(x => x)
    .map(x => +x.replace(/[\{\}~]/g, ''));
}
pxiryf3j

pxiryf3j2#

这是可能的lookarounds,JS支持。
由于我们经常重用原始模式,让我们将其存储在变量中:

const pattern = String.raw`{([^}]*(?:~\d*(?:\.\d+)?)[^}]*)}`;

不包含上述模式的字符串看起来像这样,其中[^]表示“所有字符”,类似于带有s标志的.

`(?:(?!${pattern})[^])*`

由此,我们构建了我们的lookahead和lookbehind:

// Pattern, anything that doesn't contain pattern, then header or end of string (not end of line).
const lookahead = `${pattern}(?=(?:(?!${pattern})[^])*(?:^##.+|(?![^])))`;

// Header, anything that doesn't contain pattern, then pattern itself.
const lookbehind = `(?<=^##.+$(?:(?!${pattern})[^])*)${pattern}`;

下面是我们的最后步骤:

const regex = new RegExp(`${lookbehind}|${lookahead}`, 'gm');

// Filter out unmatched groups.
[...text.matchAll(regex)].map(match => match.filter(Boolean));

试试看:

console.config({ maximize: true });

function match(string) {
  const pattern = String.raw`{([^}]*(?:~\d*(?:\.\d+)?)[^}]*)}`;
  const lookahead = `${pattern}(?=(?:(?!${pattern})[^])*(?:^##.+|(?![^])))`;
  const lookbehind = `(?<=^##.+$(?:(?!${pattern})[^])*)${pattern}`;
  const regex = new RegExp(`${lookbehind}|${lookahead}`, 'gm');
  
  console.log(regex); // Just to show you how monstrous it is.
  
  return string.matchAll(regex);
}

const text = `
## Header 1

{~1.0} Lorem ipsum dolor sit amet. Sed congue diam turpis, {~2.0} vitae congue erat accumsan nec. {~3.0}

{~4.0} Lorem ipsum dolor sit amet. Sed congue diam turpis, {~5.0} vitae congue erat accumsan nec. {~6.0}

{~7.0} Lorem ipsum dolor sit amet. Sed congue diam turpis, {~8.0} vitae congue erat accumsan nec. {~9.0}

## Header 2

{~10.0} Lorem ipsum dolor sit amet. Sed congue diam turpis, {~11.0} vitae congue erat accumsan nec. {~12.0}

{~113.0} Lorem ipsum dolor sit amet. Sed congue diam turpis, {~14.0} vitae congue erat accumsan nec. {~15.0}

{~16.0} Lorem ipsum dolor sit amet. Sed congue diam turpis, {~17.0} vitae congue erat accumsan nec. {~18.0}

## Header 3

{~19.0} Lorem ipsum dolor sit amet. Sed congue diam turpis, {~20.0} vitae congue erat accumsan nec. {~21.0}

{~22.0} Lorem ipsum dolor sit amet. Sed congue diam turpis, {~23.0} vitae congue erat accumsan nec. {~24.0}

{~25.0} Lorem ipsum dolor sit amet. Sed congue diam turpis, {~26.0} vitae congue erat accumsan nec. {~27.0}
`.trim();

console.log([...match(text)].map(match => match.filter(Boolean)));
<script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

相关问题