Text-Processing

PCRE-regex 使用 grep 排除擷取組

  • October 16, 2019

我正在使用GNU grepPCRE正則-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'行不通(同時列印foofoob)。foo|foob首先匹配foo,然後grep在 之後的輸入中查找潛在的其他匹配foo,因此從bof開始bar,因此之後再也找不到了。

上面有,我們只在交替的第二部分grep -Po '\.zoo\.\K\d+|:\s+\K.*'尋找。:<spaces><anything>這在之後的部分中確實匹配,.zoo.<digits>但這也意味著它會:<spaces><anything>在輸入中的任何位置找到那些,而不僅僅是在它們跟隨時.zoo.<digits>

不過,有一種方法可以解決這個問題,使用另一個 PCRE 特殊運算符:\G. \G匹配在主題的開頭。對於單個匹配,這等效於^,但有多個匹配(想想sed/perl中的g標誌s/.../.../g),就像-owheregrep嘗試查找該行中的所有匹配一樣,這也在前一個匹配結束後匹配。所以,如果你做到了:

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 characteror的輸入.zoo.2 blah:。您可以在交替的第一部分使用前瞻運算符來解決這個問題,並在之後尋找至少一個非空格:<spaces>(也可以$ 用來避免非字元問題)

grep -Po '^.*?\.zoo\.\K\d+(?=.*:\s+\S.*$)|(?!^)\G.*:\s+\K\S.*$'

您可能需要幾頁評論來解釋該正則表達式,所以我仍然會選擇直截了當的sed/perl解決方案……

引用自:https://unix.stackexchange.com/questions/326519