下面我将向标准输入发出正则表达式(a\b) \1
并grep
插入几个测试字符串。
$ grep -E '(a\b) \1' 啊 啊 ab 啊乙
粗体部分表示存在匹配。第二个,a ab
难倒了我。捕获组可以用文字描述为“a
后面跟着单词边界的字符”。
处理字符串 时a ab
,正则表达式引擎匹配字符a
,看到它后面跟着的不是“单词字符”,因此匹配\b
。然后它匹配一个空格。到目前为止,一切都很好。
但是,它应该检查 if \1
matches ab
,据我所知它不应该,因为接下来a
我们ab
有一个单词字符。我不明白这是怎么回事!
接受答案后,我意识到我实际上仍然不明白发生了什么事。从上面的例子出发:
$ cat tests
a bab
a ba
a ab
$ grep -E '(\ba\b) \1' tests
a ab
这告诉我捕获组包括除字符串右边缘的单词边界之外的所有内容,我仍然不明白。
答案1
问题是\1
指匹配的文本,不是一个正则表达式。在我们的例子中,匹配的文本是字符a
。由于\1
是文本,而不是正则表达式,因此它不关心a
.观察:
$ cat file
a a
a ab
$ grep -E '(a\b) \1' file
a a
a ab
如果我们想\1
成为一个单词,请为其添加一个单词边界:
$ grep -E '(a\b) \1\b' file
a a
因为\1\b
后需要一个字边界\1
,所以第二行不再匹配。
为了证明这\1
不是正则表达式,让我们尝试:
$ echo '.a' | grep -E '(.)\1'
$
但:
$ echo '..' | grep -E '(.)\1'
..
$
因此,\1
匹配.
.虽然.
通常是正则表达式活动的并且匹配任何字符,\1
但仅匹配句点。
文档
来自GNU grep 手册:
反向引用 '\n',其中 n 是单个数字,匹配之前匹配的子串由正则表达式的第 n 个带括号的子表达式。例如,“(a)\1”匹配“aa”。当与交替一起使用时,如果该组不参加比赛,则反向引用会使整个比赛失败。例如,“a(.)|b\1”将不匹配“ba”。当用 -e 或文件('-f file')给出多个正则表达式时,反向引用对于每个表达式都是本地的。 [强调。]