grep PCRE 仍然贪婪

grep PCRE 仍然贪婪

我正在搜索一个多行文本文件,并想要匹配从某个单词到另一个单词的第一个匹配项的字符串:

start
word1
word1
word1
word1
end
word2
word2
word2
start
word3
word3
word3
end

以下是我使用的:grep -Pzo "(?s)start.*?end" file.txt

它从头到尾匹配上面文本字符串中的所有内容,而我只想匹配直到第一次end出现,即:

start
word1
word1
word1
word1
end

我究竟做错了什么?

不知何故,非贪婪?量词没有像我预期的那样工作。

感谢您的时间和贡献!

答案1

A贪婪的匹配将包括从第一个start到最后一个的所有内容end,因此:

$ grep -Pzo '(?s)start.*end' file.txt
start                                                                                                                                                                                        
word1                                                                                                                                                                                        
word1                                                                                                                                                                                        
word1                                                                                                                                                                                        
word1                                                                                                                                                                                        
end                                                                                                                                                                                          
word2                                                                                                                                                                                        
word2                                                                                                                                                                                        
word2                                                                                                                                                                                        
start                                                                                                                                                                                        
word3                                                                                                                                                                                        
word3                                                                                                                                                                                        
word3                                                                                                                                                                                        
end

你实际看到的是单独的非贪婪匹配,根据-o选项在单独的“行”上输出 - 除了使用-Z,“行”实际上由空字符而不是换行符表示:

$ grep -Pzo '(?s)start.*?end' file.txt
start                                                                                                                                                                                        
word1                                                                                                                                                                                        
word1                                                                                                                                                                                        
word1                                                                                                                                                                                        
word1                                                                                                                                                                                        
endstart                                                                                                                                                                                     
word3                                                                                                                                                                                        
word3                                                                                                                                                                                        
word3                                                                                                                                                                                        
end

由于我们在这里看不到空字节,因此如果添加-b以指示“行”内两个匹配的字节偏移量,则会更清楚:

$ grep -Pzo -b '(?s)start.*?end' file.txt
0:start                                                                                                                                                                                      
word1                                                                                                                                                                                        
word1                                                                                                                                                                                        
word1                                                                                                                                                                                        
word1                                                                                                                                                                                        
end52:start                                                                                                                                                                                  
word3                                                                                                                                                                                        
word3                                                                                                                                                                                        
word3                                                                                                                                                                                        
end

由于-o输出是用空值分隔的,因此您可以通过管道传输结果head -z以获取第一个匹配项:

$ grep -Pzo '(?s)start.*?end' file.txt | head -z -n 1
start
word1
word1
word1
word1
end

或者你可以使用 perl 本身

perl -0777 -nE 'say for /(start.*?end)/s' file.txt

由于省略了标志,因此尽管有for循环,但仅打印一个匹配项g

相关内容