연속 또는 비연속 숫자로 숫자 필터링

연속 또는 비연속 숫자로 숫자 필터링

숫자로 가득 찬 파일이 있는데 각 줄에는 숫자가 있습니다. 각 숫자는 두 자리 또는 세 자리 숫자로 구성됩니다.

두 개 이상의 연속 숫자가 포함된 임의의 숫자로 파일을 필터링하고 싶습니다. 이러한 연속 숫자는 연속적(예: 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). , 숫자 자체 및 다음 또는 둘 다(순차적으로), 따라서 값$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

우분투 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'

관련 정보