首页 > 解决方案 > 使用正则表达式匹配第 N 次出现

问题描述

我正在尝试解析一个字符串并使用正则表达式匹配第 n 次出现。我目前正在处理的示例是提取字符串中的第三个美元值。现在这可能是字符串中的第二个或第四个或第 n 个值,但下面的示例特别是第三个美元值。

字符串:$4,233.65 $5,073.64 $9,307.29 $9,273.41 $0.00 $0.00 $33.88
我要匹配的值:$9,307.29
到目前为止我想出的正则表达式:(?<=\$)\S+

到目前为止的代码匹配美元符号后的每个值,所以问题是,我如何获取第三个(或第 n 个)值?

标签: regexregex-lookarounds

解决方案


从使用带有 libpcre 的 GNU grep 的命令行:

$ echo '$4,233.65 $5,073.64 $9,307.29 $9,273.41 $0.00 $0.00 $33.88' \
    |grep -Po '^(?:[^$]*\$){3}\K\S+'
9,307.29

Regex101的解释)这使用可变宽度的正向后视,并非所有语言都支持,简化为\Kfoo\Kbar与 相同(?<=foo)bar,匹配来自“foobar”的“bar”)。这会跳过两美元的金额(它使用它{3}是因为我们还包括了前导$,因为这不是所需匹配的一部分),然后匹配下一个非空白字符。

您可以在 Javascript 中使用相同的逻辑:

let test = "$4,233.65 $5,073.64 $9,307.29 $9,273.41 $0.00 $0.00 $33.88";
test.match(/^(?:[^$]*\$){3}(\S+)/)[1];  // "9,307.29"

这基本上是相同的正则表达式(在 Regex101 解释),但不是\K在比赛前使用,而是在第一个捕获组中得到了所需的部分,它match()保存在数组索引 1 中(索引 0 是整个匹配,包括前导部分,因为我们没有使用…\K(?<=…)使其为零宽度)。

但是,如果您使用的是 Javascript 之类的编程语言,则最好以编程方式进行:

let test = "$4,233.65 $5,073.64 $9,307.29 $9,273.41 $0.00 $0.00 $33.88";
test.match(/\$\S+/g)[2].substring(1);  // "9,307.29"

Regex101 的解释)这是更多的非正则表达式代码,但更干净。在这里,我只是在寻找美元值,获取第三个值(回想一下,数组是零索引的),并使用substring()剥离前导$(字符串也是零索引)。

注意,Javascript 不支持…\K(?<=…)


推荐阅读