우리는 거기 어떻게 갔나요?

우리는 거기 어떻게 갔나요?

다음과 같은 파일이 있다고 가정해 보겠습니다.

1,2,3-5,6
1,2,3-5,6,
1
1-3
1,2,3-,4,5-7
1,2,3-,4,5-7,
1,2,-3,4,5
1,2,-,3,4
1,2,,,3,4
,1,2,3

다음 규칙의 조합만 유효한 것으로 간주됩니다.

  1. 범위 [0-9]+-[0-9]+
  2. 그룹[0-9]+,[0-9]+
  3. 주문 번호[0-9]+

쉼표로 끝나는 줄도 유효한 것으로 간주되어야 합니다.

그냥 추출하고 싶은데

1,2,3-5,6
1,2,3-5,6,
1
1-3

아래 표시된 다른 라인은 규칙을 준수하지 않기 때문에

1,2,3-,4,5-7
1,2,3-,4,5-7,
1,2,-3,4,5
1,2,-,3,4
1,2,,,3,4
,1,2,3

일부 행의 범위가 불완전하고 일부 행의 그룹에 숫자가 누락되었기 때문입니다.


추신: PCRE호환 가능한 grep솔루션만 있으면 좋지만 다른 솔루션도 환영합니다.

답변1

나열된 문자열(및 그 문자열로 시작하는 문자열 )과 ,일치하는 완전한 PCRE는 다음과 같습니다.

grep -P '^([0-9]+(-[0-9]+)?(,|$))+$'

우리는 거기 어떻게 갔나요?

일치의 가장 기본적인 요소는 숫자입니다. [0-9]PCRE의 더 간단한 요소는 \d영어(ASCII) 숫자에 대한 올바른 정규식입니다. 어느아니면 아닐 수도 있습니다. 일치할 수 있다데바나가리 숫자, 예를 들어. 그런 다음 [0123456789]정확하게 작성해야 합니다 .

그 다음에연속된 숫자로 일치합니다 [0-9]+.

숫자(1, 3 또는 26) 뒤에 대시 "-"가 올 수 있고 그 뒤에 하나 이상의 숫자(역시 숫자)가 올 수 있습니다.

[0-9]+(-[0-9]+)?

여기서 ?대시 번호 순서는 선택 사항입니다.

그런 다음 각 숫자: ( 3또는 숫자 범위 4-9:) 뒤에는 쉼표 ,(여러 번)가 와야 합니다.

([0-9]+(-[0-9]+)?,)+

마지막 쉼표가 누락되었을 수 있다는 점을 제외하면:

([0-9]+(-[0-9]+)?(,|$))+

그리고 필요한 경우 앞에 쉼표가 나타날 수 있습니다.

(^|,)([0-9]+(-[0-9]+)?(,|$))+

정규식을 테스트 텍스트의 시작과 끝 부분에 고정하는 것은 매우 좋은 생각입니다.

^((^|,)([0-9]+(-[0-9]+)?(,|$))+)$

테스트하고 편집할 수 있습니다.이 웹사이트의 PCRE 정규식

선행 쉼표를 거부해야 하는 경우 다음을 사용하세요.

^(([0-9]+(-[0-9]+)?(,|$))+)$

이로 인해 정규식 기계에는 대체 해석이 필요하지 않습니다. 모두 일치해야 하며 일치하지 않는 항목은 거부됩니다.

(GNU) 확장 정규식으로 작성할 수 있습니다.

grep -E '^(([0-9]+(-[0-9]+)?(,|$))+)$'

기본 정규 표현식(BRE):

grep '^\(\([0-9]\{1,\}\(-[0-9]\{1,\}\)\{0,1\},\{0,1\}\)\{1,\}\)$'

쉼표가 ,선택사항 인 경우 {0,1}정규식 엔진은 일치 항목에 대해 몇 가지 결정을 내릴 수 있습니다.


설명적인 정규식?

(?x)공백과 주석이 포함된 보다 설명적인 정규식은 in으로 시작하여 얻을 수 있습니다.pcregrep

pcregrep '(?x)                  # tell the regex engine to allow
                                 # white space and comments.
           (?(DEFINE)            # subroutines that will be used. 
             (?<nrun> [0-9]+)    # run of digits (n-run).

              # define a range pair. A number run followed by
              # an optional ( dash and another number run )
             (?<range> (?&nrun)  (-(?&nrun))? )    # range pair.
             
             (?<sep> ,)          # separator used.
           )                     # end of definitions.

         # Actual regex to use:
         # (range) that ends in a (sep) 
         # or is at the end of the line,
         # several times (+).

         ^(  (?&range)  ((?&sep)|$)  )+$

        ' file

이 정규식(한 번 컴파일된 경우)은 원래 정규식과 정확히 동일하며 빠르게 실행됩니다. 물론 정규식을 컴파일하는 데는 (무시할 정도의) 추가 시간이 걸립니다.

테스트 예시는여기

답변2

awk원치 않는 필드나 하위 필드가 포함된 행을 삭제하면서 각 행을 쉼표로 구분된 필드로 나눈 다음 대시의 해당 필드를 하위 필드로 분할하는 데 사용됩니다 .

BEGIN { FS = "," }

{
    for (i = 1; i <= NF; ++i) {
        # Only the 1st field is allowed to be
        # empty, but only if there are further
        # fields (avoids empty lines).

        if ($i == "" && (i != 1 || NF == 1)) next

        # If the field is split on dashes, it
        # should split into no more than two
        # elements.

        if ((n = split($i, a, "-")) > 2) next

        # Each split-up element needs to be made
        # up of decimal digits only.

        for (j = 1; j <= n; ++j)
            if (a[j] !~ "^[[:digit:]]+$") next
    }

    # The current line is ok to print.

    print
}

이것은 다음과 같이 사용될 것입니다

awk -f script file

script프로그램의 위치입니다 awk.

또는 "일회성"으로:

awk -F, '{for(i=1;i<=NF;++i){if(($i==""&&(i!=1||NF==1))||((n=split($i,a,"-"))>2))next;for(j=1;j<=n;++j)if(a[j]!~"^[[:digit:]]+$")next}};1' file

5-2루프 뒤에 "역방향 범위"(예:)에 대한 검사를 쉽게 추가할 수 있습니다 j.

if (n == 2 && a[1] > a[2]) next

답변3

$ perl -n -e 'print if /^((\d+(-\d+)?)(,|$))+$/g' input.txt 
1,2,3-5,6
1,2,3-5,6,
1
1-3

또는 GNU grep과 동일합니다.

$ grep -P '^((\d+(-\d+)?)(,|$))+$' input.txt 
1,2,3-5,6
1,2,3-5,6,
1
1-3

답변4

Raku(이전 Perl_6) 사용

raku -ne '.put if m:g/^^ [ [\d+ [\-\d+]?] [\,|$$] ]+ $$/;'

입력 예:

1,2,3-5,6
1,2,3-5,6,
1
1-3
1,2,3-,4,5-7
1,2,3-,4,5-7,
1,2,-3,4,5
1,2,-,3,4
1,2,,,3,4
,1,2,3

예제 출력:

1,2,3-5,6
1,2,3-5,6,
1
1-3

Raku를 사용하는 한 가지 장점은 일치자 내의 공백 허용 오차입니다. 이렇게 하면 코드를 더 쉽게 읽을 수 있습니다. 둘째, 기본 정규식 엔진의 수정자(예: :global선행 콜론 가져오기)가 일치 구조의 시작 부분에 나타납니다 m/.../. 이는 또한 정규식을 더 읽기 쉽게 만듭니다.

위의 정규식을 문자 그대로 취하면 다음과 같습니다.'하나 이상의 숫자를 찾고 그 뒤에 선택적(0 또는 1) 대시, 하나 이상의 숫자, 쉼표 또는 줄 끝( $$)이 오고 전체 이전 패턴이 한 번 이상 반복됩니다.

이제 당신은 스스로에게 이렇게 질문할 수도 있습니다."그래서 뭐요? Perl5처럼 생겼어요."위의 코드는 Perl5/PCRE를 거의 직접 번역한 것이기 때문입니다. 실제로 Raku(예: Perl6)에는 일반적인 정규식 문제를 해결하는 데 사용할 수 있는 새로운 "구분 기호" 관용어(예: "수정 수량자")가 있습니다. 재치 있게:

raku -ne '.put if m:g/^^ [\d+ [\-\d+]? ]+ % "," $$/;'

또는

raku -ne '.put if m:g/^^ [\d+ [\-\d+]? ]+ %% "," $$/;'

첫 번째 줄에서는 %왼쪽 패턴 사이에 쉼표 구분 기호가 삽입되는 감지 일치를 사용합니다. 두 번째 줄 using 은 %%동일한 작업을 수행하지만 후행 쉼표도 허용합니다. 당신의 선택.

Perl 전문가 Damian Conway는 Raku(일명 Perl6)가 완전히 새로운 스타일의 정규식을 대표한다고 지적합니다. 시도해 보면 동의할 수도 있습니다.

https://docs.raku.org/언어/regexes#Modified_Quantifier:_%,_%%
https://youtu.be/ubvSjW6Nyqk
https://raku.org/

관련 정보