使用 grep,我试图匹配由两个字符组成的行,一个是重复的,然后是另一个,但仅当第一个字符出现的次数等于第二个字符的出现次数时才匹配。
例如,假设我只能匹配两个字符,例如“0”和“1”。现在想象一下,如果有 n 个 '0' 字符,那么后面必须有 n 个 '1' 字符。例如:
都会匹配。但:
不匹配。
我一直在玩捕获组并通过 perldoc 搜索有关 grep -P 的更多信息,但还没有找到任何解决我问题的线索 - 至少使用 grep。
给定这些约束,我如何制作 grep 命令来匹配字符串?
编辑:
有关说明的更新,请参阅下面的编辑
这是 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)
该0和1可以制成其可作为外部参数如果需要,可以提供,(所以它可以是任何语法,变量a和b等等)。
它在问题的示例输入上按预期打印,因此在输入上 file
0011 000111 00000000001111111111 01 011 1100 110001
它打印
0011 000111 00000000001111111111 01
(输出中的最后一个空行是中间的空行,之后没有更多行匹配)
†也就是说,不使用在正则表达式中运行代码的棘手功能,这会使其变得更加复杂。如果您仍然希望使用它,请在 perlre 和 perlretut中查看它 。
或者,这也可以使用regex 中的递归来完成,具有相似(或稍低?)的复杂性。
这一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)