正则表达式:仅匹配最深的列表级别

404*_*und 4 grep regular-expression

我编制了游戏中所需的材料清单,从最上层到最原始的成分。然而,现在我正在寻找一种快速统计数字的方法。

21 reinforced alloy
    21 damascus steel
        21 steel
            21 iron dust
            21 carbon
            21 iron
        21 iron dust
        21 carbon
        21 iron
    21 hardened metal
        21 damascus steel
            21 steel
                21 iron dust
                21 carbon
                21 iron
            21 iron dust
            21 carbon
            21 iron
        21 duralmin
            21 aluminum dust
            21 copper dust
            21 aluminum
                21 aluminum dust
        21 compressed carbon
            84 carbon
        21 aluminum bronze
            21 aluminum dust
            21 bronze
                21 copper dust
                21 tin dust
                21 copper
            21 aluminum
                21 aluminum dust
    21 corinthian bronze
        21 silver dust
        21 gold dust
        21 copper dust
        21 bronze
            21 copper dust
            21 tin dust
            21 copper
    21 solder
        21 lead dust
        21 tin dust
        21 lead
            21 lead dust
    21 billon
        21 silver dust
        21 copper dust
        21 silver
            21 silver dust
    21 gold 24 carat
Run Code Online (Sandbox Code Playgroud)

最高层并不重要,因为我正在寻找我需要收集的原材料。例如,21 hardened metal21 damascus steel并不重要,因为我正在寻找 的总数42 damascus steel,这也无关紧要,因为我正在寻找42 iron dust, 42 carbon, 和42 iron(此示例不计算列表的其余部分),原材料总数。

到目前为止,我在正则表达式测试网站上做到了这一点,但最终我希望能够使用grep,这样我就不必打开网站来进行计数。我想要得到类似“碳出现 5 次,这是匹配线”这样我可以更容易地计算,因为如果我知道碳出现 5 次,其中 4 次是,21 carbon1 次是84 carbon,我现在可以轻松计算出我总共需要21*4 + 84 = 168 carbon.

我正在尝试计算没有另一行且后面有大量选项卡的行,因为如果有的话,那么它就不是原材料。

/(\t+)\d+ aluminum\n(?!\1)/g(用我试图找到的任何原材料替换“铝”)

但这并没有发现任何东西。有没有办法实现我想用正则表达式实现的目标?如果是这样,怎么办?

感谢您的时间。


我不确定是否将其放在 SO 或 SE 上,但考虑到我最终希望能够使用,grep我认为这可能是更合适的地方。

Sté*_*las 5

如果你想使用类似 perl 的正则表达式,为什么不使用真正的正则表达式:

<your-file perl -l -0777 -ne '
  while (m{^(\s*+)(\d+) (.*)$(?!\n\1\s)}mg) {
    $count{$3} += $2
  }
  END {
    printf "%4d %s\n", $count{$_}, $_ for sort keys %count
  }'
Run Code Online (Sandbox Code Playgroud)

这使:

  84 aluminum dust
 168 carbon
  42 copper
 105 copper dust
  21 gold 24 carat
  21 gold dust
  84 iron
  84 iron dust
  42 lead dust
  63 silver dust
  63 tin dust
Run Code Online (Sandbox Code Playgroud)

-0777 -n意味着整个输入都被吸进了$_. m操作符的 ultiline 标志使得m{...}^匹配$在每行的开头和结尾,$_而不仅仅是在 的开头和结尾$_。如果没有该s 标志,则.与换行符不匹配,但请注意,\s如果输入中有空行,这可能会导致这里出现问题。

\s*+是 的非回溯版本\s*。这里并不是绝对必要的,因为 ( \d+) 后面的内容不能匹配空格。

Standardgrep不支持类似 perl 的正则表达式,例如您正在使用的那些\d和perl RE 运算符,但您可以使用它恰好也支持多行模式:(?!\1)pcregrep-o-M

<your-file pcregrep -Mo '^(\s*+)\K.*$(?!\n\1\s)'
Run Code Online (Sandbox Code Playgroud)

您仍然需要通过管道进行其他操作,例如perl进行awk求和,因此这与用于perl所有操作相比没有什么优势。

如果缩进可能混合有制表符和空格,您可能希望输入通过其中之一expandunexpand首先将它们合并为空格或制表符。默认情况下,他们认为制表位与大多数终端或浏览器一样相隔 8 列(但 stackexchange 则不同,令人烦恼的是,它们相隔 4 列),但请参阅-t更改此设置的选项。