다음과 같은 파일이 있다고 가정해 보겠습니다.
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
다음 규칙의 조합만 유효한 것으로 간주됩니다.
- 범위
[0-9]+-[0-9]+
- 그룹
[0-9]+,[0-9]+
- 주문 번호
[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/