我有一个充满数字的文件,每行都有数字。每个数字由两位或三位数字组成。
我想按任何具有两个或更多连续数字的数字过滤掉该文件。这些连续的数字可以是连续的(例如127、215、781),也可以是不连续的(例如506)。连续数字的顺序并不重要。它可以从小到大(例如127)或从大到小(例如215)。
例如:
127
215
781
874
370
01
10
142
506
94
预期输出:
370
94
因为:
127 # Has two sequential and consecutive digits (1 and 2)
215 # Has two sequential and consecutive digits (1 and 2)
781 # Has two sequential and consecutive digits (7 and 8)
874 # Has two sequential and consecutive digits (7 and 8)
370 # Keep
01 # Has two sequential and consecutive digits (0 and 1)
10 # Has two sequential and consecutive digits (0 and 1)
142 # Has two sequential and non-consecutive digits (1 and 2)
506 # Has two sequential and non-consecutive digits (5 and 6)
94 # Keep
答案1
将awk
FS 设置为空字符串(使用空 FS 的效果是每个 POSIX 未定义的行为,并且根据awk
您使用的版本可能会产生不同的结果)。以下是在 GNU 中测试的awk
:
awk -F '' '{
is_sequential=0;
for (i=2; i<=NF; i++)
is_sequential+=($0 ~ $i-1 || $0 ~ $i+1)
}!is_sequential' infile
我们正在检查整行中的每个数字是否与 number-1或 number+1$i
相等,这意味着如果在一行中看到一个数字或两个数字,那么我们发现至少有两个数字彼此相邻(第一个、数字 本身和下一个或或两者(顺序),因此值$i-1
$i+1
number-1
number+1
$i
$i-1
$i+1
是顺序的变量将递增,否则将保持为 0。
使用!is_sequential
,我们打印该值未更改的行(该值仍然是0
,没有看到至少两个连续的数字);也可以看看awk 脚本末尾的“1”是什么意思
或者使用任何 awk:
awk '{
is_sequential=0;
for (i=1; i<=length(); i++) {
num=substr($0, i, 1)
is_sequential+=($0 ~ num-1 || $0 ~ num+1)
}
}!is_sequential' infile
答案2
你可以尝试一下
awk '
{split ("", N) # delete array N
L = 1 # initialise boolean L to TRUE
for (i=1; i<=length($1); i++){ # for each digit
P = substr($1, i, 1)
if (N[P-1] || N[P+1]){ # if contiguous digit exists,
L = 0
break # set L to FALSE; and quit the for loop
}
N[P] = 1
}
}
L
' file
输出:
370
94
或者
awk '
{split ("", N)
L = 1
for (i=1; i<=length; i++)
N[substr($0,i,1)] = 1 # set all N elements for the digits in string
for (i=0; i<9; i++)
if (N[i] + N[i+1] == 2) { # check for two adjacent elements to be TRUE
L = 0
break
}
}
L
' file
输出:
370
94
在 Ubuntu 18.04 上测试
答案3
在这里,由于组合列表相对较小,您不妨在 ERE 交替中考虑它们:
grep -vE '0.*1|1.*[02]|2.*[13]|3.*[24]|4.*[35]|5.*[46]|6.*[57]|7.*[68]|8.*[79]|9.*8'
与此相同,perl
但在正则表达式内部使用 Perl 代码(??{...})
来匹配下一个或上一个数字:
perl -ne 'print unless /([0-8]).*(??{$1+1})/ || /([1-9]).*(??{$1-1})/'
使用 sed,您可以将连续对的列表附加到模式空间,并使用反向引用来查找匹配项:
sed -ne '1{x;s/$/0123456789876543210/;x;}' -e 'G;/\(.\).*\(.\).*\n.*\1\2/!P'