[0-9], [[: digit :]]와 \ d의 차이점


35

에서 정규 표현식에 위키 백과 문서 , 그것은 보인다 [[:digit:]]= [0-9]= \d.

그들이 같지 않은 상황은 무엇입니까? 차이점은 무엇입니까?

몇 가지 연구를 한 후에는 대괄호 표현 [:expr:]이 로케일에 따라 달라집니다.


3
하지 않습니다 당신을 연결하는 위키 백과 문서 질문에 대한 답변은? 다른 정규식 프로세서 / 엔진은 문자 클래스에 대해 다른 구문을 지원합니다.
igal

@igal Wiki는 차이점이 있지만 세부 사항은 제공하지 않습니다. 이삭과 같은 디테일을 묻고 있다고 스리 그는 말했다. 나는 GNU 버전이든 아니든 grep, sed, awk의 차이점에 꽤 관심이 있습니다.
harbinn

답변:


40

예, [[:digit:]]~ [0-9]~입니다 \d(여기서 ~는 근사값을 나타냄).
대부분의 프로그래밍 언어 (지원되는 경우) \d[[:digit:]](동일).
\d보다 일반적입니다 [[:digit:]](하지 POSIX에서하지만 GNU에있다 grep -P).

예를 들어 UNICODE 에는 많은 숫자 가 있습니다 .

123456789 # Hindu-Arabic 아라비아 숫자
٠١٢٣٤٥٦٧٨٩ # ARABIC-INDIC
۰۱۲۳۴۵۶۷۸۹ # EXTENDED ARABIC-INDIC/PERSIAN
߀߁߂߃߄߅߆߇߈߉ # NKO DIGIT
०१२३४५६७८९ # DEVANAGARI

이는 모두 포함될 수있다[[:digit:]]\d.

대신 [0-9]일반적으로 ASCII 숫자 0123456789입니다.


Perl, Java, Python, C [[:digit:]]와 같은 많은 언어가 있습니다 \d. 예를 들어,이 펄 코드는 위의 모든 숫자와 일치합니다 :

$ a='0123456789 ٠١٢٣٤٥٦٧٨٩ ۰۱۲۳۴۵۶۷۸۹ ߀߁߂߃߄߅߆߇߈߉ ०१२३४५६७८९'

$ echo "$a" | perl -C -pe 's/[^\d]//g;' ; echo
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९

Numeric및 의 유니 코드 속성이있는 모든 문자를 선택하는 것과 같습니다 digits.

$ echo "$a" | perl -C -pe 's/[^\p{Nd}]//g;' ; echo
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९

어떤 grep이 재생할 수 있는지 (특정 버전의 pcre는 Perl과 다른 내부의 숫자 코드 포인트 목록이있을 수 있음) :

$ echo "$a" | grep -oP '\p{Nd}+'
0123456789
٠١٢٣٤٥٦٧٨٩
۰۱۲۳۴۵۶۷۸۹
߀߁߂߃߄߅߆߇߈߉
०१२३४५६७८९

다음을 보려면 [0-9]로 변경하십시오.

$ echo "$a" | grep -o '[0-9]\+'
0123456789

POSIX

특정 POSIX BRE 또는 ERE의 경우 :
\d(하지 POSIX이 아니라 GNU에 지원되지 않습니다 grep -P). [[:digit:]]POSIX는 숫자 문자 클래스에 대응하기 위해 요구되며, ISO C에서는 문자 0부터 9까지가 필요합니다. 그래서 단지 C에서 로케일 모든 [0-9], [0123456789], \d[[:digit:]]정확히 같은 의미한다. 는 [0123456789]어떤 가능한 오해가 없습니다 [[:digit:]]더 유틸리티에서 사용할 수 있으며 만 의미하는 것이 일반적이다 [0123456789]. 이 \d유틸리티는 일부 유틸리티에서 지원됩니다.

에 관해서는 [0-9], 범위 표현의 의미는 C 로케일에서 POSIX에 의해서만 정의됩니다. 다른 로케일에서는 다를 수 있습니다 (코드 포인트 순서 또는 데이터 정렬 순서 또는 다른 것).

껍질

일부 구현에서는 범위가 일반 ASCII 순서 (예 : ksh93)와 다른 것으로 이해 될 수 있습니다.

$ LC_ALL=en_US.utf8 ksh -c 'a="'"$a"'";echo "${a//[0-9]}"'
  ۹ ߀߁߂߃߄߅߆߇߈߉ ९

그리고 그것은 기다리고있는 버그의 확실한 원인입니다.


실제로 POSIX 시스템 iswctype()및 POSIX 유틸리티의 BRE / ERE / 와일드 카드에서 [0-9] 및 [[: digit :]]는 0123456789에서만 일치합니다. 그리고 그것은 표준의 다음 개정판에서 밝혀 질 것입니다
Stéphane Chazelas

perl\d유니 코드 모드가 다른 스크립트의 십진수와 일치 한다는 것을 알지 못했습니다 . 고마워 PCRE를 사용하면 (*UCP)GNU에서 grep -Po '(*UCP)\d'또는 grep -Po '(*UCP)[[:digit:]]유니 코드 속성을 기반으로하는 클래스를 참조하십시오 .
Stéphane Chazelas

[:digit:]구문은 사용자가 숫자로 간주하는 현지화를 사용하고 싶다는 제안에 동의합니다 . [:digit:]실제로는 [0-9]절대로 0123456789와 일치하고 싶고 절대 일치 ٠١٢٣٤٥٦٧٨٩하지 않으며 10 진수와 일치하고 싶은 유스 케이스를 생각할 수 없기 때문에 실제로 사용 하지 않습니다. POSIX 유틸리티가있는 모든 스크립트에서. zsh ML에 대한 현재 토론[:blank:] 도 참조하십시오 . 그 캐릭터 클래스는 약간 혼란입니다.
Stéphane Chazelas

13

이것은 숫자를 정의하는 방법에 따라 다릅니다. [0-9]ASCII로만되는 경향이 있습니다 (또는 ASCII 또는 ASCII의 상위 집합이 아닌 다른 비트 표현 (EBCDIC)을 가진 ASCII와 동일한 10 자리). \d반면에 일반 숫자 (이전 버전의 Perl 또는 /a정규식 플래그를 사용 하는 최신 버전의 Perl ) 일 수도 있고 유니 코드 일치 일 수도 있고 \p{Digit}그보다 더 큰 숫자 세트 [0-9]이거나 /\d/a일치 할 수도 있습니다.

$ perl -E 'say "match" if 42 =~ m/\d/'
match
$ perl -E 'say "match" if "\N{U+09EA}" =~ m/\d/'
match
$ perl -E 'say "match" if "\N{U+09EA}" =~ m/\d/a'
$ perl -E 'say "match" if "\N{U+09EA}" =~ m/[0-9]/'
$ 

perldoc perlrecharclass 자세한 내용을 보거나 문제가있는 언어의 설명서를 참조하여 언어가 어떻게 작동하는지 확인하십시오.

그러나 더 많은 것이 있습니다! 로케일은 또한 \d일치 하는 내용이 다를 \d수 있으므로 전체 유니 코드 세트보다 적은 자릿수를 일치시킬 수 있으며 (일반적으로) 포함 [0-9]합니다. 이것은 isdigit(3)( [0-9])와 isnumber(3)( [0-9와 로케일의 다른 것 )의 C 차이와 유사합니다 .

숫자가 아닌 경우에도 숫자 값을 얻기 위해 호출 할 수 있습니다 [0-9].

$ perl -MUnicode::UCD=num -E 'say num(4)'
4
$ perl -MUnicode::UCD=num -E 'say num("\N{U+09EA}")'
4
$ 

생각 isnumber()BSD의 일이,에 기초 적어도되는 사람 페이지 로 들린다
ilkkachu

나는 예, BSD 바이어스의 뭔가를 할
thrig

/ a 플래그는 유니 코드 숫자 목록 만 일치시키기위한 특정 제한 기입니다 . / a 수정자는 \ d를 ASCII 0에서 9 까지만 일치 시키는 데 사용할 수 있습니다 . 따라서 정확히 동일하게 일치하도록 강제하고 있습니다 [0-9].
Isaac

5

다른 의미 [0-9], [[:digit:]]그리고 \d다른 답변에 제시되어있다. 여기에 정규식 엔진 구현에 차이점을 추가하고 싶습니다.

            [[:digit:]]    \d
grep -E               ✓     ×
grep -P               ✓     ✓
sed                   ✓     ×
sed -E                ✓     ×

그래서 [[:digit:]]항상 작동합니다 , \d따라 달라집니다. 그렙의 매뉴얼에서는 그 언급 한 것 [[:digit:]]그냥 0-9C로케일.

PS1 : 더 알고 있다면 표를 확장하십시오.

PS2 : GNU grep 3.1 및 GNU 4.4가 테스트에 사용됩니다.


2
1) grep및의 많은 버전이 있으며 sedGNU 버전과 다른 버전의 차이가 가장 큽니다. 그것의 버전을 언급 한 경우 대답은 더 유용 할 수 있습니다 grep그리고 sed그것은을 의미합니다. 또는 그 문제의 원인은 해당 테이블의 출처입니다. 이 이미지로 그것을 필요로 아무것도 포함하지 않기 때문에 2) 그 테이블뿐만 아니라 텍스트로 복사 할 수 있습니다
ilkkachu

@ilkkachu 1) 최신 GNU grep 3.1 및 GNU 4.4가 테스트에 사용됩니다. 2) 테이블을 만드는 방법이 없습니다. @ muru가 테이블을 예쁜 텍스트 형식으로 변환 한 것 같습니다.
하얼빈

@ harbinn 답변으로 수정하십시오.
Dan D.

@DanD. 추가 된 버전 정보 관심을 끌기위한 thx
harbinn

1
python 내장 re모듈은 [[: digit :]]를 지원하지 않지만 라이브러리에 추가는 regex그것을 지원 하므로 항상 작동 할 때 약간 낄낄 거립니다. 항상 posix 불만 상황에서 작동합니다.
Steve Barnes

4

이론적 차이점은 다른 답변에서 이미 잘 설명되었으므로 실제 차이점 을 설명하는 것으로 남아 있습니다 .

다음은 숫자 일치와 관련된 일반적인 사용 사례입니다.


원샷 데이터 추출

일부 숫자를 크런치하려고 할 때 숫자 자체가 어색한 형식의 텍스트 파일로되어있는 경우가 종종 있습니다. 프로그램에서 사용하기 위해 추출하려고합니다. 숫자 형식 (파일을보고)과 현재 로케일 을 알 수 있으므로 작업이 완료 되는 한 양식을 사용하는 것이 좋습니다. \d가장 적은 키 스트로크가 필요하므로 매우 일반적으로 사용됩니다.

입력 소독

신뢰할 수없는 사용자 입력이있을 수 있으며 (웹 양식 일 수도 있음) 놀라움이 없는지 확인해야합니다. 데이터베이스의 숫자 필드에 저장하거나 쉘 명령의 매개 변수로 사용하여 서버에서 실행할 수 있습니다. 이 경우 [0-9]가장 제한적이고 예측 가능한 것이기 때문에 정말로 원합니다 .

데이터 유효성 검사

"위험한"어떤 것에도 사용하지 않을 약간의 데이터가 있지만 그것이 숫자인지 아는 것이 좋습니다. 예를 들어 프로그램에서 사용자가 주소를 입력 할 수 있으며 입력에 집 번호가없는 경우 가능한 오타를 강조 표시하려고합니다. 이 경우 가능한 한 넓게 가고 싶을 [[:digit:]]것입니다.


숫자 일치에 가장 일반적인 3 가지 사용 사례 인 것 같습니다. 중요한 것을 놓쳤다 고 생각되면 의견을 남겨주십시오.


좋은 작업, 보안 문제 등 ReDoS 또는 다른 사람으로 관련되어
frams
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.