PCRE-regex 使用 grep 排除擷取組
我正在使用
GNU grep
PCRE正則-P
表達式支持來匹配文件中的字元串。輸入文件的行包含以下字元串:FOO_1BAR.zoo.2.someString:More-RandomString (string here too): 0.45654343
我想從上面的行
2
中擷取數字。0.45654343
我用了一個正則表達式grep -Po ".zoo.\K[\d+](.*):\ (.*)$" file
但這給我帶來了一個結果
2.someString:More-RandomString (string here too): 0.45654343
我能夠從第一個擷取組中獲取第一個數字作為
2
,並且還可以匹配行尾的擷取組。但我無法跳過兩個擷取組之間的單詞/行。我知道一個事實,我有一個小組
(.*)
在中間捕捉這些詞。我試圖做的是包括另一個\K
忽略它grep -Po ".zoo.\K[\d+](.*):\K (.*)$" file
但這只給了我第二個擷取組作為
0.556984
.還有一個非擷取組,
(?:)
語法為grep -Po ".zoo.\K[\d+](?=.someString:More-RandomString (string here too)):\ (.*)$"
但這什麼也沒給我。我在這裡想念什麼?
grep
的名字出現在g/re/p
ed
命令之後。它的主要目的是列印匹配正則表達式的行。編輯這些行的內容不是它的職責。你有sed
(流編輯器)或awk
為此。現在,一些
grep
實現,從 GNU 開始grep
添加了一個-o
選項來列印每行的匹配部分(由正則表達式匹配的部分,而不是它的擷取組)。你grep
又得到了一些像 GNU 的實現(帶有-P
)或者pcregrep
支持 PCRE 的正則表達式。
pcregrep
實際上添加了一個-o<n>
選項來列印擷取組的內容。所以你可以這樣做:pcregrep -o1 -o2 --om-separator=' ' '.zoo.(\d+).*:\s+(.*)'
但在這裡,明顯的標準解決方案是使用
sed
:sed -n 's/^.*\.zoo\.\([0-9]\{1,\}\).*:[[:space:]]\{1,\}/\1 /p'
或者,如果您想要 perl 正則表達式,請使用 perl:
perl -lne 'print "$1 $2" if /\.zoo\.(\d+).*:\s+(.*)/'
使用 GNU
grep
,如果您不介意匹配出現在不同的行上,您可以這樣做:$ grep -Po '\.zoo\.\K\d+|:\s+\K.*' < file 2 0.45654343
請注意,雖然
\K
重置匹配部分的開始,但這並不意味著您可以擺脫交替重疊的兩個部分。grep -Po '.zoo. (\K\d+| *.:\K.* )'
行不通,就像
echo foobar | grep -Po 'foo|foob'
行不通(同時列印foo
和foob
)。foo|foob
首先匹配foo
,然後grep
在 之後的輸入中查找潛在的其他匹配foo
,因此從b
of開始bar
,因此之後再也找不到了。上面有,我們只在交替的第二部分
grep -Po '\.zoo\.\K\d+|:\s+\K.*'
尋找。:<spaces><anything>
這在之後的部分中確實匹配,.zoo.<digits>
但這也意味著它會:<spaces><anything>
在輸入中的任何位置找到那些,而不僅僅是在它們跟隨時.zoo.<digits>
。不過,有一種方法可以解決這個問題,使用另一個 PCRE 特殊運算符:
\G
.\G
匹配在主題的開頭。對於單個匹配,這等效於^
,但有多個匹配(想想sed
/perl
中的g
標誌s/.../.../g
),就像-o
wheregrep
嘗試查找該行中的所有匹配一樣,這也在前一個匹配結束後匹配。所以,如果你做到了:grep -Po '\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
where
(?!^)
是一個負前瞻運算符,表示*不在行的開頭,*僅\G
在先前成功(非空)匹配之後匹配,因此.*:\s+\K.*
僅在它遵循先前成功匹配時才匹配,並且只能是因為交替的.foo.<digits>
另一部分匹配直到行尾。在這樣的輸入上:
.zoo.1.zoo.2 tar: blah
那將輸出:
1 2 blah
儘管。如果您不希望這樣,您還希望交替的第一部分僅在行首匹配。就像是
grep -Po '^.*?\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
仍然會輸出
2
類似.zoo.2 no colon character
or的輸入.zoo.2 blah:
。您可以在交替的第一部分使用前瞻運算符來解決這個問題,並在之後尋找至少一個非空格:<spaces>
(也可以$
用來避免非字元問題)grep -Po '^.*?\.zoo\.\K\d+(?=.*:\s+\S.*$)|(?!^)\G.*:\s+\K\S.*$'
您可能需要幾頁評論來解釋該正則表達式,所以我仍然會選擇直截了當的
sed
/perl
解決方案……