grep - 我如何匹配仅使用两个字符但每个字符出现相同次数的正则表达式?
grep - How would I match a regex using only two characters, but with each character occuring the same number of times?
我正在使用 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。
仅使用您展示的示例,如果您对 awk
满意,您可以尝试以下操作。
awk 'match([=10=],/^0+/){num1=RLENGTH;match([=10=],/1+/);if(num1==RLENGTH){print}}' Input_file
说明: 为以上添加详细说明。
awk ' ##Starting awk program from here.
match([=11=],/^0+/){ ##Using match function to match starting zeroes here.
num1=RLENGTH ##Creating num1 here with rlength.
match([=11=],/1+/) ##Matching all ones now.
if(num1==RLENGTH){ print } ##Checking condition if num1 is equal to current length then print the line.
}
' Input_file ##mentioning Input_file name here.
请参阅下面的 EDIT 更新说明
这是 Perl 单行代码而不是 grep
perl -wne'print if /^((.)\g{-1}+)((.)\g{-1}+)$/ and length == length ' file
匹配的长度比较显然是在正则表达式之外完成的;我看不出它可以很好地在内部完成†,而且我看不出使用非正则表达式的代码有什么问题:)
这与单个字符 (ab
) 不匹配,什么没有真正意义,什么似乎被排除在问题之外。锚点(^
和 $
)使得它只能匹配具有两个字符的字符串,这似乎是指定的。
那个\g{-1}
是一个relative backreference。它匹配上次捕获的相同子模式,这是我们需要的,而不是简单的反向引用 (\g1
)。
这是需要的,因为\g1
指的是第一个捕获,parens组最先开始(最左边),这是对整个模式的捕获。 (我们 可以 使用 \g2
但将它们数掉是不好的做法。)
这可以通过使用命名引用变得更好,但这样也会更复杂。
EDIT 在澄清之后,它必须首先是 0
s,然后是相同数量的 1
s,并且 0
-重复计数(所以空行),当然还有 1
-重复(所以 01
)。这大大简化了事情,因为
perl -wne'print if /^(0*)(1*)$/ and length == length ' file
如果需要,0
和 1
可以作为外部参数提供的变量(所以它可以是任何语法,a
和 b
等)。
它在问题的示例输入上按预期打印,因此在输入 file
0011
000111
00000000001111111111
01
011
1100
110001
它打印
0011
000111
00000000001111111111
01
(输出中最后一个空行是中间的空行,之后没有更多的行匹配)
† 也就是说,如果不使用 运行 在正则表达式中编码的棘手功能,这会使它变得更加复杂。如果您仍然想玩那个,请看
in perlre
和
in perlretut.
或者,这也可以使用 recursion in regex 来完成,具有相似(或更小?)的复杂性。
这 awk
一行应该可以完成工作:
cat file
0011
000111
00000000001111111111
011
1100
11000
awk '/^0*1*$/ && gsub(/0/, "&") == gsub(/1/, "&")' file
0011
000111
00000000001111111111
或者如果你想打印可能有 1
s 后跟 0
s 的数字,那么使用:
# awk command
awk '/^(0*1*|1*0*)$/ && gsub(/0/, "&") == gsub(/1/, "&")' file
0011
000111
00000000001111111111
1100
gsub
函数returns替换次数
由于您使用了 grep
标签,这里有一个 gnu grep
命令和 -P
(PCRE 递归)正则表达式:
grep -P '^(0(?1)?1|1(?1)?0)?$' file
0011
000111
00000000001111111111
1100
使用真正的正则表达式不可能做到这一点,但由于递归的存在,使用 Perl 正则表达式可以做到这一点。
/
^ (?&BALANCED)?+ \z
(?(DEFINE)
(?<BALANCED> 0 (?&BALANCED)?+ 1 )
)
/x
简述:
/^((?:0(?1)1)?+)\z/
演示:
$ perl -nle'print if /^((?:0(?1)1)?+)\z/' <<'.'
0011
000111
00000000001111111111
011
1100
110001
.
0011
000111
00000000001111111111
参见 。
PCRE 也支持递归。因此,您可以使用以下内容:
grep -P '^((?:0(?1)1)?+)$'
演示:
$ grep -P '^((?:0(?1)1)?+)$' <<'.'
0011
000111
00000000001111111111
011
1100
110001
.
0011
000111
00000000001111111111
我正在使用 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。
仅使用您展示的示例,如果您对 awk
满意,您可以尝试以下操作。
awk 'match([=10=],/^0+/){num1=RLENGTH;match([=10=],/1+/);if(num1==RLENGTH){print}}' Input_file
说明: 为以上添加详细说明。
awk ' ##Starting awk program from here.
match([=11=],/^0+/){ ##Using match function to match starting zeroes here.
num1=RLENGTH ##Creating num1 here with rlength.
match([=11=],/1+/) ##Matching all ones now.
if(num1==RLENGTH){ print } ##Checking condition if num1 is equal to current length then print the line.
}
' Input_file ##mentioning Input_file name here.
请参阅下面的 EDIT 更新说明
这是 Perl 单行代码而不是 grep
perl -wne'print if /^((.)\g{-1}+)((.)\g{-1}+)$/ and length == length ' file
匹配的长度比较显然是在正则表达式之外完成的;我看不出它可以很好地在内部完成†,而且我看不出使用非正则表达式的代码有什么问题:)
这与单个字符 (ab
) 不匹配,什么没有真正意义,什么似乎被排除在问题之外。锚点(^
和 $
)使得它只能匹配具有两个字符的字符串,这似乎是指定的。
那个\g{-1}
是一个relative backreference。它匹配上次捕获的相同子模式,这是我们需要的,而不是简单的反向引用 (\g1
)。
这是需要的,因为\g1
指的是第一个捕获,parens组最先开始(最左边),这是对整个模式的捕获。 (我们 可以 使用 \g2
但将它们数掉是不好的做法。)
这可以通过使用命名引用变得更好,但这样也会更复杂。
EDIT 在澄清之后,它必须首先是 0
s,然后是相同数量的 1
s,并且 0
-重复计数(所以空行),当然还有 1
-重复(所以 01
)。这大大简化了事情,因为
perl -wne'print if /^(0*)(1*)$/ and length == length ' file
如果需要,0
和 1
可以作为外部参数提供的变量(所以它可以是任何语法,a
和 b
等)。
它在问题的示例输入上按预期打印,因此在输入 file
0011 000111 00000000001111111111 01 011 1100 110001
它打印
0011 000111 00000000001111111111 01
(输出中最后一个空行是中间的空行,之后没有更多的行匹配)
† 也就是说,如果不使用 运行 在正则表达式中编码的棘手功能,这会使它变得更加复杂。如果您仍然想玩那个,请看 in perlre 和 in perlretut.
或者,这也可以使用 recursion in regex 来完成,具有相似(或更小?)的复杂性。
这 awk
一行应该可以完成工作:
cat file
0011
000111
00000000001111111111
011
1100
11000
awk '/^0*1*$/ && gsub(/0/, "&") == gsub(/1/, "&")' file
0011
000111
00000000001111111111
或者如果你想打印可能有 1
s 后跟 0
s 的数字,那么使用:
# awk command
awk '/^(0*1*|1*0*)$/ && gsub(/0/, "&") == gsub(/1/, "&")' file
0011
000111
00000000001111111111
1100
gsub
函数returns替换次数
由于您使用了 grep
标签,这里有一个 gnu grep
命令和 -P
(PCRE 递归)正则表达式:
grep -P '^(0(?1)?1|1(?1)?0)?$' file
0011
000111
00000000001111111111
1100
使用真正的正则表达式不可能做到这一点,但由于递归的存在,使用 Perl 正则表达式可以做到这一点。
/
^ (?&BALANCED)?+ \z
(?(DEFINE)
(?<BALANCED> 0 (?&BALANCED)?+ 1 )
)
/x
简述:
/^((?:0(?1)1)?+)\z/
演示:
$ perl -nle'print if /^((?:0(?1)1)?+)\z/' <<'.'
0011
000111
00000000001111111111
011
1100
110001
.
0011
000111
00000000001111111111
参见
PCRE 也支持递归。因此,您可以使用以下内容:
grep -P '^((?:0(?1)1)?+)$'
演示:
$ grep -P '^((?:0(?1)1)?+)$' <<'.'
0011
000111
00000000001111111111
011
1100
110001
.
0011
000111
00000000001111111111