过滤掉具有连续或不连续数字的数字

过滤掉具有连续或不连续数字的数字

我有一个充满数字的文件,每行都有数字。每个数字由两位或三位数字组成。

我想按任何具有两个或更多连续数字的数字过滤掉该文件。这些连续的数字可以是连续的(例如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

awkFS 设置为空字符串(使用空 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+1number-1number+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'

相关内容