連続または非連続数で数値をフィルタリング

連続または非連続数で数値をフィルタリング

数字でいっぱいのファイルがあり、各行には数字があります。各数字は2桁または3桁の数字で構成されています。

複数の連続した数字を含むランダムな数字でファイルをフィルタリングしたいと思います。これらの連続した数字は連続的(例えば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

FSを空の文字列に設定しますawk。空の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

行全体のすべての数字が数字-1または数字+ 1と等しいことを確認してください$i。つまり、行に 1 つの数字または 2 つの数字が表示されている場合は、隣に少なくとも 2 つの数字が見つかりました (セクション 1)。 、数値自体、および次または両方(順次)、したがって値$i-1$i+1number-1number+1$i$i-1$i+1順次変数は増加し、そうでなければゼロのままです。

を使用して!is_sequential値が変更されていない行を印刷します(値はまだあり、少なくとも02つの連続した数字は表示されません)。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'

関連情報