Gyp*_*aut 2 grep regular-expression pcre
假设我有一个如下文件
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
Run Code Online (Sandbox Code Playgroud)
只有以下规则的组合才被视为有效:
[0-9]+-[0-9]+[0-9]+,[0-9]+[0-9]+以逗号结尾的行也应该被认为是有效的
我只想提取
1,2,3-5,6
1,2,3-5,6,
1
1-3
Run Code Online (Sandbox Code Playgroud)
由于下面显示的其他行不符合规则
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
Run Code Online (Sandbox Code Playgroud)
因为有些行的范围不完整,有些行缺少组中的数字
PS:唯一PCRE兼容的grep解决方案会很棒,但也欢迎其他解决方案
与您列出的字符串(以及以 a 开头的字符串)匹配的完整 pcre,可能是:
grep -P '^((^|,)([0-9]+(-[0-9]+)?(,|$))+)$'
Run Code Online (Sandbox Code Playgroud)
要匹配的最基本元素是数字,假设[0-9]或\dPCRE 中更简单的元素是英文 (ASCII) 数字的正确正则表达式。这也可能不是。例如,它可以匹配梵文数字。那么你需要写:[0123456789]准确地说。
然后,一串数字将被匹配[0-9]+。
在一个数字(1 或 3 或 26)之后可能有一个破折号“-”,后跟一个或几个数字(又是一个数字):
[0-9]+(-[0-9]+)?
Run Code Online (Sandbox Code Playgroud)
其中?使破折号序列可选。
然后,这些数字中的每一个:(3或数字范围:)4-9后面应该跟一个逗号,(多次):
([0-9]+(-[0-9]+)?,)+
Run Code Online (Sandbox Code Playgroud)
除了最后一个逗号可能会丢失:
([0-9]+(-[0-9]+)?(,|$))+
Run Code Online (Sandbox Code Playgroud)
并且,如果需要,可能会出现一个前导逗号:
(^|,)([0-9]+(-[0-9]+)?(,|$))+
Run Code Online (Sandbox Code Playgroud)
将正则表达式锚定到测试文本的开头和结尾是一个很好的主意:
^((^|,)([0-9]+(-[0-9]+)?(,|$))+)$
Run Code Online (Sandbox Code Playgroud)
您可以在本站测试和编辑PCRE 正则表达式
如果应拒绝前导逗号,请使用:
^(([0-9]+(-[0-9]+)?(,|$))+)$
Run Code Online (Sandbox Code Playgroud)
这对正则表达式机器没有任何可选的解释。所有都必须匹配,任何不匹配的都会被拒绝。
它可以写成一个(GNU)扩展正则表达式:
grep -E '^(([0-9]+(-[0-9]+)?(,|$))+)$'
Run Code Online (Sandbox Code Playgroud)
作为基本正则表达式 (BRE):
grep '^\(\([0-9]\{1,\}\(-[0-9]\{1,\}\)\{0,1\},\{0,1\}\)\{1,\}\)$'
Run Code Online (Sandbox Code Playgroud)
如果逗号,是可选的{0,1},正则表达式引擎可能会决定匹配什么。
使用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
}
Run Code Online (Sandbox Code Playgroud)
这将被用作
awk -f script file
Run Code Online (Sandbox Code Playgroud)
其中,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
Run Code Online (Sandbox Code Playgroud)
您可以5-2在j循环后轻松添加对“向后范围”(例如)的检查:
if (n == 2 && a[1] > a[2]) next
Run Code Online (Sandbox Code Playgroud)