쉼표로 구분된 숫자와 일치하는 전역 패턴

쉼표로 구분된 숫자와 일치하는 전역 패턴

쉼표로 구분된 숫자와 일치하는 전역 패턴을 작성하고 싶습니다. 패턴은 어떤 모습일까요?

여기 몇 가지 예가 있어요

5
5,8,13

다음으로 시작했지만 일치하는 항목을 얻지 못하여 몇 가지 문제가 있습니다.

var="8,13,21"
echo "var: $var"
if [[ "$var" == ^*([[:digit:]])+(,+[[:digit:]])$ ]]; then
  echo "match"
fi

답변1

bash 매뉴얼은 [[ expression ]]구문을 설명합니다.

==AND 연산자를 사용하는 경우 !=연산자 오른쪽의 문자열은 패턴으로 처리되며 마치 extglob 셸 옵션이 활성화된 것처럼 패턴 일치에 설명된 규칙에 따라 일치됩니다.

여기서 쉘 옵션은 extglobksh 스타일 확장 글로브를 나타냅니다.

  ?(pattern-list)
         Matches zero or one occurrence of the given patterns
  *(pattern-list)
         Matches zero or more occurrences of the given patterns
  +(pattern-list)
         Matches one or more occurrences of the given patterns
  @(pattern-list)
         Matches one of the given patterns
  !(pattern-list)
         Matches anything except one of the given patterns

내가 의심하는 것은 +[[:digit:]]1개 이상의 숫자를 일치시키려는 것입니다 +([[:digit:]]). 따라서 쉼표 뒤에 1개 이상의 숫자가 오고, 모두 0회 이상이어야 *(,+([[:digit:]])합니다 .

+([[:digit:]])*(,+([[:digit:]]))

쉼표로 구분된 목록을 형성하기 위해 1개 이상의 숫자와 0개 이상의 쉼표로 구분된 숫자가 뒤따르는 일치 항목을 찾습니다.

^glob 표현식은 앵커 를 사용하지 않는다는 점에 유의하십시오 $. 이는 항상 전체 행입니다. 부분 일치를 원할 경우 *표현식을 와일드카드로 묶어야 합니다.


1 이것은 bash 4.1부터 새로운 기능입니다. 이전 버전에서는 shopt -s extglob이러한 확장된 전역 연산자를 내부 및 외부에서 명시적으로 사용할 수 있도록 해야 했습니다 [[...]].

답변2

사용하는 구문은 와일드카드와 정규식 구문이 혼합된 것처럼 보입니다.

Bash의 RegEx 일치를 사용하려는 경우(위에서 언급한 대로)댓글에서), 비교 연산자를 사용해야 합니다 =~. 이 경우 테스트 구성의 올바른 구문은 다음과 같습니다.

if [[ "$var" =~ ^([[:digit:]])+(,[[:digit:]]+)*$ ]]; then
...

이는 여러 측면에서 시연한 시도와 다릅니다.

  • 현재 시도에서는 ,+[[:digit:]]"하나 이상의 쉼표와 숫자"가 일치합니다.
  • 처음에 RegEx가 *길을 잃은 것 같습니다. 리터럴과 일치하지 않는 한 *잘못되었거나( *RegEx에서는 "가능한 문자 조합"이 아니라 "0개 이상의 선행 문자"를 의미함) 중복됩니다. ( 일치시키려면 $.*앵커를 제거하고 간단히 선언할 수도 있습니다 ([[:digit:]])+(,+[[:digit:]])$).

반면에 실제로 "확장된 와일드카드" 구문( 연산자 의 구성 [[ ... ]]에서 기본적으로 허용되는 ==) 을 사용하려는 경우

  • ^앵커( 및 ) 사용이 $잘못되었습니다. 앵커는 정규식에만 유효하며 확장된 형식에서도 글로빙 구문의 일부가 아닙니다. 또한 전역 패턴은 기본적으로 전체 문자열에 적용되므로 필요하지 않습니다.
  • 또한,모든"반복 지정자"(예: *또는 +)가 앞에 오는 항목은 괄호 안에 배치해야 하므로 명령문에 괄호 세트가 누락됩니다 +[[:digit:]].

따라서 이 경우 일치하는 글로브는 다음과 같아야 합니다.

if [[ "$var" == +([[:digit:]])*(,+([[:digit:]])) ]]; then echo "match"; fi

답변3

sh완벽을 기하기 위해 명령문에서 표준 와일드카드 case( kshism)를 사용하여 이 작업을 수행 하려면 [[...]]그 반대를 수행해야 합니다.

case $var in
  ('' | *[!,0123456789]* | *, | ,* | *,,* ) echo WRONG;;
  (*) echo RIGHT;;
esac

+표준 glob 모드 ( ##zsh 또는 ksh와 동일) 에는 ERE와 동등한 기능이 없습니다 .+(...)

그러나 다음 명령을 사용하여 정규식 일치를 수행할 수 있습니다 awk

rematch() { awk -- 'BEGIN{exit(ARGV[1] !~ ARGV[2])}' "$@"; }

if rematch ",$var" '^(,[0123456789]+)+$'; then
  echo RIGHT
else
  echo WRONG
fi

1 ANSI C 이스케이프 시퀀스(예: , , (펄 스타일 단어 경계가 아닌 백스페이스의 경우)) awk도 이해하는(또는 이해하기 위한 것이지만 모두가 이 방식으로 사용하는 것은 아님) 표준 확장 정규식의 변형을 얻습니다 . .\n\t\b

관련 정보