grep - 如何仅使用两个字符匹配正则表达式,但每个字符出现的次数相同?

Mat*_*ian 6 regex perl grep

使用 grep,我试图匹配由两个字符组成的行,一个是重复的,然后是另一个,但仅当第一个字符出现的次数等于第二个字符的出现次数时才匹配。

例如,假设我只能匹配两个字符,例如“0”和“1”。现在想象一下,如果有 n 个 '0' 字符,那么后面必须有 n 个 '1' 字符。例如:

  • ''
  • '0011'
  • '000111'
  • '00000000001111111111'

都会匹配。但:

  • '011'
  • '1100'
  • '110001'

不匹配。

我一直在玩捕获组并通过 perldoc 搜索有关 grep -P 的更多信息,但还没有找到任何解决我问题的线索 - 至少使用 grep。

给定这些约束,我如何制作 grep 命令来匹配字符串?

编辑:

  • 在此示例中,根据“紧随其后”的限制,0 应位于 1 之前
  • 空字符串也应该是一个匹配案例,因为根据示例限制,当有 n 个 0 时,应该有 n 个 1,因此当有零个 0 时,应该有零个 1。

zdi*_*dim 5

有关说明的更新,请参阅下面的编辑


这是 Perl one-liner 而不是 grep

perl -wne'print if /^((.)\g{-1}+)((.)\g{-1}+)$/ and length $1 == length $3' file
Run Code Online (Sandbox Code Playgroud)

匹配的长度比较显然是在正则表达式之外完成的;我不认为它可以在内部很好地完成,而且我认为使用不是正则表达式的代码没有任何问题:)

这与单个字符 ( ab)不匹配,什么是没有意义的,什么似乎被排除在问题之外。锚点 (^$) 使它只能匹配具有两个字符的字符串,这似乎是指定的。

\g{-1}是一个相对反向引用。它匹配上次捕获的相同子模式,这是我们需要的,而不是简单的反向引用 ( \g1)。

这是需要的,因为\g1指的是第一次捕获,括号集最先开始(最左边),也就是整个模式的捕获。(我们可以使用,\g2但将它们计算在内是不好的做法。)

这可以通过使用命名引用变得更好,但它也会更加复杂。


编辑   根据澄清,它必须0先是 s 然后是相同数量的1s,并且0-repetitions 计数(所以是空行),1当然还有-repetition (所以01)。这大大简化了问题,因为

perl -wne'print if /^(0*)(1*)$/ and length $1 == length $2' file
Run Code Online (Sandbox Code Playgroud)

01可以制成其可作为外部参数如果需要,可以提供,(所以它可以是任何语法,变量ab等等)。

它在问题的示例输入上按预期打印,因此在输入上 file

0011

000111
00000000001111111111
01

011
1100
110001

它打印

0011

000111
00000000001111111111
01

(输出中的最后一个空行是中间的空行,之后没有更多行匹配)


也就是说,不使用在正则表达式中运行代码的棘手功能,这会使其变得更加复杂。如果您仍然希望使用它,请在 perlreperlretut中查看它 。

或者,这也可以使用regex 中的递归来完成,具有相似(或稍低?)的复杂性。


anu*_*ava 3

这一awk行应该可以完成这项工作:

cat file

0011

000111
00000000001111111111
011
1100
11000
Run Code Online (Sandbox Code Playgroud)
awk '/^0*1*$/ && gsub(/0/, "&") == gsub(/1/, "&")' file

0011
000111
00000000001111111111
Run Code Online (Sandbox Code Playgroud)

或者,如果您想打印可能有1s 后跟0s 的数字,请使用:

# awk command
awk '/^(0*1*|1*0*)$/ && gsub(/0/, "&") == gsub(/1/, "&")' file

0011
000111
00000000001111111111
1100
Run Code Online (Sandbox Code Playgroud)

gsub函数返回替换数。


由于您已经使用了grep标签,因此这是一个gnu grep带有-P(PCRE递归)正则表达式的命令:

grep -P '^(0(?1)?1|1(?1)?0)?$' file

0011
000111
00000000001111111111
1100
Run Code Online (Sandbox Code Playgroud)

grep 正则表达式演示

  • *011* 和 *110001* 一定不能匹配。事实上 *1100* 必须不匹配可能是OP问题中的错误。除了空行之外,您返回与预期答案相反的结果 (2认同)
  • 谢谢@bruno,我之前打印了不匹配的内容,但现在反转了。我不确定 OP 是否也希望“1”后面跟着“0”,但我也在我的答案中包含了该选项。 (2认同)