n자리 그룹을 찾는 방법(n개 이하)

n자리 그룹을 찾는 방법(n개 이하)

저는 Linux를 배우고 있는데 혼자서는 해결하지 못할 것 같은 과제가 있습니다. 여기있어:

연속해서 4개의 숫자를 포함하지만 4개 이하의 숫자를 포함하는 파일에서 한 줄을 grep합니다.

이 문제에 어떻게 접근해야 할지 잘 모르겠습니다. 특정 숫자는 검색할 수 있지만 문자열의 금액은 검색할 수 없습니다.

답변1

이 질문을 해석하는 방법에는 두 가지가 있습니다. 두 가지 경우 모두 다루겠습니다. 다음 줄을 표시하고 싶을 수도 있습니다.

  1. 더 긴 숫자 시퀀스의 일부가 아닌 4개의 숫자 시퀀스를 포함하는 것,또는
  2. 4자리 시퀀스를 포함하지만 더 이상 숫자 시퀀스가 ​​아닌(개별적으로도 아님)

예를 들어 (1)은 표시되지만 1234a56789(2)는 표시되지 않습니다.


더 긴 숫자 시퀀스의 일부가 아닌 4개의 숫자 시퀀스를 포함하는 모든 행을 표시하려는 경우 한 가지 방법은 다음과 같습니다.

grep -P '(?<!\d)\d{4}(?!\d)' file

이는 다음을 사용합니다.펄 정규 표현식, 우분투의grep(GNU grep)을 통해 지원됩니다 -P. 와 같은 텍스트와 일치하지 않으며 그 일부인 또는 와도 12345일치하지 않습니다 .12342345그러나 그것은 1234in 과 일치할 것입니다 1234a56789.

Perl 정규식에서:

  • \d[0-9]는 임의의 숫자를 의미합니다( 또는 이라고 짧게 표현함 [[:digit:]]).
  • x{4}성냥x4 번. ( { }구문은 Perl 정규식에만 국한되지 않고 확장 정규식에도 있습니다 grep -E.) 따라서 \d{4}와 동일합니다 \d\d\d\d.
  • (?<!\d)너비가 0인 부정적인 Look-Behind 어설션입니다. 이는 "앞에 가 오지 않는 한 \d"을 의미합니다.
  • (?!\d)너비가 0인 부정 예측 어설션입니다. 이는 "뒤에 가 오지 않는 한 \d"을 의미합니다.

(?<!\d)(?!\d)네 자리 숫자 이외의 텍스트는 일치하지 않습니다 . 대신, (함께 사용하면) 긴 숫자 시퀀스의 일부인 경우 4개의 숫자 시퀀스가 ​​자체적으로 일치하는 것을 방지합니다.

가장 오른쪽이나 가장 왼쪽의 4자리 하위 시퀀스가 ​​여전히 일치하기 때문에 뒤돌아보기나 미리보기만 사용하는 것만으로는 충분하지 않습니다.

사용하면 좋은 점 중 하나뒤돌아보기 및 미리보기 어설션패턴이 주변 텍스트가 아닌 4자리 시퀀스 자체와만 일치한다는 것입니다. 이는 색상 강조 표시(옵션 포함)를 사용할 때 유용합니다 --color.

ek@Io:~$ grep -P '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
12345abc789d0123e4

기본적으로우분투에서는 각 사용자 alias grep='grep --color=auto'~.bashrc파일. 따라서 grep다음 으로 시작하는 간단한 명령을 실행하면 색상이 자동으로 강조 표시됩니다.별칭확장됨) 그리고표준 출력~이다터미널(이게 뭐야--color=auto)을 확인합니다. 일치하는 항목은 일반적으로 빨간색 음영으로 강조 표시됩니다(거의주홍), 이탤릭체로 굵은 글씨로 표시했습니다.스크린샷은 다음과 같습니다.
12345abc789d0123e4가 출력되고 0123이 빨간색으로 강조 표시된 grep 명령을 보여주는 스크린샷.

grep그리고 다음을 사용하면 전체 줄이 아닌 일치하는 텍스트만 인쇄 할 수도 있습니다 -o.

ek@Io:~$ grep -oP '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
0123

대체 방법,없이Look-Behind 및 Look-Ahead 어설션

그러나 다음과 같은 경우에는

  1. grepPerl 정규식을 지원하지 않거나 -P사용을 원하지 않는 시스템에서도 실행되는 명령이 필요합니다 .그리고
  2. 특별히 네 자리 숫자를 일치시킬 필요는 없습니다. 이는 일반적으로 일치하는 항목이 포함된 행을 표시하는 것이 목표인 경우에 해당됩니다.그리고
  3. 조금 덜 우아한 솔루션은 괜찮습니다

...그러면 다음을 사용하여 이를 달성할 수 있습니다.확장 정규식대신에:

grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file

이는 4자리 숫자와 숫자가 아닌 문자(또는 해당 줄의 시작 또는 끝)와 일치합니다. 구체적으로:

  • [0-9]는 임의의 숫자(예 [[:digit:]]: 또는 \dPerl 정규식) 와 일치하며 {4}"4번"을 의미합니다. 따라서 [0-9]{4}4자리 시퀀스와 일치합니다.
  • [^0-9]0~ 범위에 없는 문자와 일치합니다 9. 이는 Perl 정규 표현식의 [^[:digit:]](또는 ) 과 동일합니다 \D.
  • ^, 괄호 안에 나타나지 않으면 [ ]줄의 시작 부분과 일치합니다. 마찬가지로 $줄의 끝과 일치합니다.
  • |수단또는괄호는 대수학에서처럼 그룹화를 위한 것입니다. 따라서 (^|[^0-9])줄의 시작 부분이나 숫자가 아닌 문자와 일치하고 ($|[^0-9])줄의 끝이나 숫자가 아닌 문자와 일치합니다.

[0-9]{4}따라서 일치 항목은 다음과 같은 4자리 시퀀스( )가 동시에 포함된 행에서만 발생합니다 .

  • 줄의 시작 부분에 또는 숫자가 아닌 문자( (^|[^0-9]))가 앞에 오는 경우,그리고
  • 줄 끝에 있거나 숫자가 아닌 문자( ($|[^0-9]))가 뒤에 옵니다.

반면에 4자리 시퀀스를 포함하지만 다음을 포함하지 않는 모든 행을 표시하려는 경우어느4개 이상의 숫자 시퀀스(단 4개 숫자의 다른 시퀀스와 분리된 하나라도)인 경우 개념적으로 목표는 한 패턴과 일치하지만 다른 패턴에는 일치하지 않는 행을 찾는 것입니다.

따라서 단일 패턴으로 수행하는 방법을 알고 있더라도 다음과 같은 것을 사용하는 것이 좋습니다.매트의두 번째 제안은 grep두 패턴을 별도로 사용하는 것입니다.

그렇게 할 때 Perl 정규식의 고급 기능 중 어떤 것도 큰 이점을 얻지 못하므로 사용하지 않는 것이 더 나을 수도 있습니다. 그러나 위의 스타일을 유지하면서 다음은매트의 솔루션\d다음 대신 (및 중괄호) 사용 [0-9]:

grep -P '\d{4}' file | grep -Pv '\d{5}'

를 사용하므로 [0-9],매트의 방식grep이식성이 더 좋습니다. Perl 정규식을 지원하지 않는 시스템에서 작동합니다 . 대신 [0-9](또는 )을 사용 하고 계속해서 사용하면 matt 방식의 이식성을 좀 더 간결하게 얻을 수 있습니다.[[:digit:]]\d{ }

grep -E '[0-9]{4}' file | grep -Ev '[0-9]{5}'

단일 패턴을 사용한 대체 방법

grep정말로 다음 명령을 선호한다면

  1. 단일 정규 표현식을 사용합니다.(두 개의 grep가 a로 구분되지 않음파이프, 위와 같이)
  2. 적어도 하나의 4자리 숫자 시퀀스를 포함하는 행을 표시하려면,
  3. 그러나 5개(또는 그 이상) 숫자로 구성된 시퀀스는 없습니다.
  4. 숫자뿐만 아니라 전체 줄을 일치시키는 것도 괜찮습니다(아마도 괜찮을 것입니다).

...그런 다음 다음을 사용할 수 있습니다.

grep -Px '(\d{0,4}\D)*\d{4}(\D\d{0,4})*' file

플래그 는 전체 줄이 일치하는 줄만 표시 -x합니다 (어떤 줄도 아닌).grep포함하는경기).

이 경우에는 간결 \d하고 명확성이 크게 향상된다고 생각하기 때문에 Perl 정규식을 사용했습니다. 그러나 를 지원하지 않는 \D시스템에 이식할 수 있는 것이 필요한 경우 and (또는 and ) 로 바꿀 수 있습니다 .grep-P[0-9][^0-9][[:digit:]][^[:digit]]

grep -Ex '([0-9]{0,4}[^0-9])*[0-9]{4}([^0-9][0-9]{0,4})*' file

이러한 정규식이 작동하는 방식은 다음과 같습니다.

  • 중간에 \d{4}또는 [0-9]{4}4자리 숫자의 하나의 시퀀스와 일치합니다. 이 중 하나 이상이 있을 수 있지만 적어도 하나는 있어야 합니다.

  • 왼쪽에서 (\d{0,4}\D)*또는 4개 이하의 숫자 뒤에 숫자가 아닌 숫자가 오는 ([0-9]{0,4}[^0-9])*0개 이상의 ( ) 인스턴스와 일치합니다 . *0자리(즉, 아무것도 없음)는 "4자리 이하"에 대한 가능성 중 하나입니다. 이 일치(ㅏ)빈 문자열 또는(비)임의의 문자열종결숫자가 아니고 4자리 이상의 시퀀스를 포함하지 않습니다.

    \d{4}중앙 (또는 ) 의 바로 왼쪽에 있는 텍스트는 [0-9]{4}비어 있거나 숫자가 아닌 숫자로 끝나야 하기 때문에 중앙이 \d{4}바로 왼쪽에 다른(5번째) 숫자가 있는 4개의 숫자와 일치하는 것을 방지합니다.

  • 오른쪽에서 (\D\d{0,4})*or는 숫자가 아닌 숫자와 4개 이하의 숫자(이전과 같이 4개, 3개, 2개, 1개 또는 전혀 없을 수도 있음)의 0개 이상의 인스턴스와 ([^0-9][0-9]{0,4})*일치합니다 . *이 일치(ㅏ)빈 문자열 또는(비)임의의 문자열시작숫자가 아니고 4자리 이상의 시퀀스를 포함하지 않습니다.

    \d{4}중앙 (또는 ) 바로 오른쪽에 있는 텍스트는 [0-9]{4}비어 있거나 숫자가 아닌 숫자로 시작해야 하기 때문에 중앙이 \d{4}바로 오른쪽에 다른(5번째) 숫자가 있는 4개의 숫자와 일치하는 것을 방지합니다.

이렇게 하면 4자리 시퀀스가 ​​어딘가에 존재하고 5자리 이상의 시퀀스가 ​​어디에도 존재하지 않도록 보장됩니다.

이런 식으로 하는 것이 나쁘거나 잘못된 것은 아닙니다. 그러나 아마도 이 대안을 고려해야 하는 가장 중요한 이유는 위와 같이 제안된 대로(또는 유사한)를 대신 사용하는 것의 이점을 명확히 한다는 것입니다.grep -P '\d{4}' file | grep -Pv '\d{5}'매트의 대답.

이렇게 하면 한 가지 항목만 포함하고 다른 항목은 포함하지 않는 줄을 선택하는 것이 목표라는 것이 분명해집니다. 또한 구문이 더 간단합니다(그래서 많은 독자/유지관리자가 더 빨리 이해할 수 있습니다).

답변2

이렇게 하면 연속으로 4개의 숫자가 표시되지만 그 이상은 표시되지 않습니다.

grep '[0-9][0-9][0-9][0-9][^0-9]' file

^는 그렇지 않음을 의미합니다.

여기에는 문제가 있습니다. 어떻게 해결해야 할지 잘 모르겠습니다. 숫자가 줄의 끝이면 표시되지 않습니다.

그러나이 추악한 버전은 해당 경우에 작동합니다

grep '[0-9][0-9][0-9][0-9]' file | grep -v [0-9][0-9][0-9][0-9][0-9]

답변3

file시스템의 실제 파일 이름으로 바꾸어 아래 명령을 시도해 볼 수 있습니다 .

grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file

당신은 또한 확인할 수 있습니다이 튜토리얼grep 명령을 더 많이 사용하려면

답변4

grepPerl 정규식( )을 지원하지 않는 경우 -P다음 쉘 명령을 사용하십시오.

grep -w "$(printf '[0-9]%.0s' {1..4})" file

printf '[0-9]%.0s' {1..4}4 번 생산 됩니다 [0-9]. 이 방법은 숫자가 길고 패턴을 반복하고 싶지 않을 때 유용합니다( 4찾을 숫자로 바꾸면 됩니다).

를 사용하면 -w전체 단어를 찾습니다. 그러나 와 같은 영숫자 문자열에 관심이 있다면 패턴 끝에 1234a추가하십시오 . 예:[^0-9]

grep "$(printf '[0-9]%.0s' {1..4})[^0-9]" file

사용은 $()기본적으로명령 대체. 이것을 확인하세요우편printf패턴이 어떻게 반복되는지 확인하세요 .

관련 정보