我们是怎么到达那里的?

我们是怎么到达那里的?

假设我有一个如下所示的文件

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解决方案会很棒,但也欢迎其他解决方案

答案1

与您列出的字符串(以及以 开头的字符串,)匹配的完整 PCRE 可能是:

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

我们是怎么到达那里的?

匹配的最基本元素是数字,我们假设[0-9],或者 PCRE 中更简单的元素\d,是英语 (ASCII) 数字的正确正则表达式。哪个也可能不是。它可以匹配天城文数字, 例如。那么你需要写:[0123456789]准确地说。

然后,一个连续数字将匹配为[0-9]+.

数字(1 或 3 或 26)后可以是破折号“-”,后跟一个或多个数字(又是一个数字):

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

其中?使短划线数字序列可选。

然后,每个数字:(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

该正则表达式(一旦编译)与原始正则表达式完全相同,并且运行速度同样快。当然,编译正则表达式需要花费(可以忽略不计的)额外时间。

测试示例是这里

答案2

用于awk将每行分解为逗号分隔的字段,然后将破折号上的这些字段拆分为子字段,同时丢弃包含不需要的字段或子字段的行:

BEGIN { FS = "," }

{
    for (i = 1; i <= NF; ++i) {
        # Only the 1st field is allowed to be
        # empty, but only if there are further
        # fields (avoids empty lines).

        if ($i == "" && (i != 1 || NF == 1)) next

        # If the field is split on dashes, it
        # should split into no more than two
        # elements.

        if ((n = split($i, a, "-")) > 2) next

        # Each split-up element needs to be made
        # up of decimal digits only.

        for (j = 1; j <= n; ++j)
            if (a[j] !~ "^[[:digit:]]+$") next
    }

    # The current line is ok to print.

    print
}

这会像这样使用

awk -f script file

script程序所在的位置awk

或者,作为“一次性”:

awk -F, '{for(i=1;i<=NF;++i){if(($i==""&&(i!=1||NF==1))||((n=split($i,a,"-"))>2))next;for(j=1;j<=n;++j)if(a[j]!~"^[[:digit:]]+$")next}};1' file

5-2您可以轻松地在循环后添加对“向后范围”(例如)的检查j

if (n == 2 && a[1] > a[2]) next

答案3

$ perl -n -e 'print if /^((\d+(-\d+)?)(,|$))+$/g' input.txt 
1,2,3-5,6
1,2,3-5,6,
1
1-3

或者,与 GNU grep 相同:

$ grep -P '^((\d+(-\d+)?)(,|$))+$' input.txt 
1,2,3-5,6
1,2,3-5,6,
1
1-3

答案4

使用 Raku(以前称为 Perl_6)

raku -ne '.put if m:g/^^ [ [\d+ [\-\d+]?] [\,|$$] ]+ $$/;'

输入示例:

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,2,3-5,6
1,2,3-5,6,
1
1-3

使用 Raku 的一个优点是匹配器内的空白容忍度。这使得代码更具可读性。其次,基本正则表达式引擎的修饰符(例如:global获取前导冒号)并出现在匹配结构的开头m/.../。这也使得正则表达式更具可读性。

从字面上看上面的正则表达式,它说:'查找一个或多个数字,后跟一个可选的(零或一个)破折号,一个或多个数字,后跟逗号或行尾 ( $$),整个前面的模式重复一个或-更多次。

现在你可能会问自己,“那又怎样?看起来就像 Perl5 一样。”那是因为上面的代码几乎是 Perl5/PCRE 的直接翻译。事实上,Raku(即 Perl6)有一个新的“分隔符”习惯用法(即“修改量词”),可以用来解决常见的正则表达式问题。以机智:

raku -ne '.put if m:g/^^ [\d+ [\-\d+]? ]+ % "," $$/;'

或者

raku -ne '.put if m:g/^^ [\d+ [\-\d+]? ]+ %% "," $$/;'

第一行使用%检测匹配,其中逗号分隔符插入到左侧的模式之间。第二行 using%%执行相同的操作 - 但也允许尾随逗号。你的选择。

Perl 大师 Damian Conway 指出,Raku(即 Perl6)代表了正则表达式的一种全新风格:如果您尝试一下,您可能会同意。

https://docs.raku.org/language/regexes#Modified_quantifier:_%,_%%
https://youtu.be/ubvSjW6Nyqk
https://raku.org/

相关内容