Grep

使用正則表達式匹配重複模式

  • September 11, 2021

假設我有一個如下文件

1,2,3-5,6
1,2,3-5,6,
1
1-3
1,2,3-,4,5-7
1,2,3-,4,5-7,
1,2,-3,4,5
1,2,-,3,4
1,2,,,3,4
,1,2,3

只有以下規則的組合才應被視為有效:

  1. 範圍 [0-9]+-[0-9]+
  2. 團體[0-9]+,[0-9]+
  3. 單號[0-9]+

以逗號結尾的行也應該被認為是有效的

我只想提取

1,2,3-5,6
1,2,3-5,6,
1
1-3

由於下面顯示的其他行不符合規則

1,2,3-,4,5-7
1,2,3-,4,5-7,
1,2,-3,4,5
1,2,-,3,4
1,2,,,3,4
,1,2,3

因為有些行的範圍不完整,所以有些行缺少組中的數字


PS:僅PCRE兼容的grep解決方案會很棒,但也歡迎其他解決方案

與您列出的字元串(以及以 a 開頭的字元串,)匹配的完整 pcre 可能是:

grep -P '^([0-9]+(-[0-9]+)?(,|$))+$'

我們是怎麼到那裡的?

要匹配的最基本元素是數字,假設[0-9]\dPCRE 中更簡單的元素是英語 (ASCII) 數字的正確正則表達式。這還不如不是。例如,它可以匹配梵文數字。然後你需要寫:[0123456789]準確地說。

然後,一系列數字將與 匹配[0-9]+

在一個數字(1 或 3 或 26)之後,可以是一個破折號“-”,後跟一個或多個數字(又是一個數字):

[0-9]+(-[0-9]+)?

其中?dash-number 序列是可選的。

然後,每個數字:(3或數字範圍:)4-9後面應該跟一個逗號,(多次):

([0-9]+(-[0-9]+)?,)+

除了最後一個逗號可能會失去:

([0-9]+(-[0-9]+)?(,|$))+

並且,如果需要,可能會出現前導逗號:

(^|,)([0-9]+(-[0-9]+)?(,|$))+

將正則表達式錨定到測試文本的開頭和結尾是一個非常好的主意:

^((^|,)([0-9]+(-[0-9]+)?(,|$))+)$

您可以在本站測試和編輯PCRE 正則表達式

如果應該拒絕前導逗號,請使用:

^(([0-9]+(-[0-9]+)?(,|$))+)$

這沒有給正則表達式機器留下可選的解釋。所有都必須匹配,任何不匹配的都會被拒絕。

它可以寫成(GNU)擴展正則表達式:

grep -E '^(([0-9]+(-[0-9]+)?(,|$))+)$'

作為基本正則表達式 (BRE):

grep '^\(\([0-9]\{1,\}\(-[0-9]\{1,\}\)\{0,1\},\{0,1\}\)\{1,\}\)$'

如果逗號,是可選{0,1}的,正則表達式引擎可能會決定匹配什麼。


描述性正則表達式?

一個更具描述性的正則表達式,帶有空格和註釋,可以通過以(?x)in開頭pcregrep

pcregrep '(?x)                  # tell the regex engine to allow
                                # white space and comments.
          (?(DEFINE)            # subroutines that will be used. 
            (?<nrun> [0-9]+)    # run of digits (n-run).

             # define a range pair. A number run followed by
             # an optional ( dash and another number run )
            (?<range> (?&nrun)  (-(?&nrun))? )    # range pair.
            
            (?<sep> ,)          # separator used.
          )                     # end of definitions.

        # Actual regex to use:
        # (range) that ends in a (sep) 
        # or is at the end of the line,
        # several times (+).

        ^(  (?&range)  ((?&sep)|$)  )+$

       ' file

此正則表達式(一旦編譯)與原始正則表達式完全相同,並且執行速度同樣快。當然,編譯正則表達式需要(可以忽略不計的)額外時間。

測試範例在這裡

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