유니코드 숫자

유니코드 숫자

존재하다정규 표현식에 관한 Wikipedia 기사, [[:digit:]]== 인 것 같습니다 [0-9].\d

어떤 상황에서 그들은 동등하지 않습니까? 차이점은 무엇입니까?

몇 가지 조사를 통해 한 가지 차이점은 대괄호 표현이 [:expr:]로케일에 따라 다르다는 것입니다.

답변1

네, 그렇습니다 [[:digit:]]~~ (여기서 ~는 근사치를 의미합니다). 대부분의 프로그래밍 언어에서 (지원되는 언어)[0-9]\d

\d ≡ `[[:digit:]]`            # (is identical to, it is a short hand for).  

(POSIX에서는 사용 가능 하지만 POSIX에서는 사용할 수 없음) \d보다 인스턴스 수가 적습니다.[[:digit:]]grep -P

유니코드 숫자

가지다유니코드로 된 많은 숫자, 예를 들어:

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

이들 모두포함될 수 있다에서 [[:digit:]]또는 에서 \d, 심지어 어떤 경우에는 [0-9].


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에 의해서만 정의됩니다. 다른 로케일에서는 다를 수 있습니다(아마도 코드 포인트 순서나 데이터 정렬 등).

[0123456789]

모든 ASCII 숫자에 대한 가장 기본적인 옵션입니다.
항상 유효합니다. (AFAICT) 알려진 실패 사례가 없습니다.

영어 숫자만 일치합니다: 0123456789.

[0-9]

[0-9]일반적 으로 ASCII 숫자로 생각됩니다 0123456789.
어떤 경우에는 이것이 매우 잘못된 경우가 있습니다. 다음과 같이 "C"가 아닌 일부 시스템(2020년 6월) 시스템의 로케일에 있는 Linux입니다.

생각하다:

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

grep가장 많이 허용되는 것을 찾아 보십시오 .

$ echo "$str" | grep -o '[0-9]\+'
0123456789
٠١٢٣٤٥٦٧٨
۰۱۲۳۴۵۶۷۸
߀߁߂߃߄߅߆߇߈
०१२३४५६७८

sed에 문제가 있습니다. 삭제해야 0123456789하지만 거의 모든 번호를 삭제해야 합니다. 이는 대부분의 숫자를 허용하지만 일부 9(???)는 허용하지 않음을 의미합니다.

$ echo "$str" | sed 's/[0-9]\{1,\}//g'
 ٩ ۹ ߉ ९

expr도 sed와 같은 문제를 안고 있습니다.

expr "$str" : '\([0-9 ]*\)'             # also matching spaces.
0123456789 ٠١٢٣٤٥٦٧٨

그리고 편집자

printf '%s\n' 's/[0-9]/x/g' '1,p' Q | ed -v <(echo "$str")
105
xxxxxxxxxx xxxxxxxxx٩ xxxxxxxxx۹ xxxxxxxxx߉ xxxxxxxxx९

[[:숫자:]]

Perl, Java, Python, C 등 다양한 언어가 있습니다. 여기서 [[:digit:]](및 \d)에는 확장된 의미가 필요합니다. 예를 들어, 다음 Perl 코드는 위의 모든 숫자와 일치합니다.

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

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

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

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

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

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

껍데기

일부 구현에서는 범위를 일반적인 ASCII 순서(예: ksh93)와 다른 것으로 이해할 수 있습니다(2018년 5월 빌드(AT&T Research) 93u+ 2012-08-01에서 테스트한 경우).

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

현재(2020년 6월), debian의 동일한 패키지 ksh93(동일 버전 sh(AT&T Research) 93u+ 2012-08-01):

$ LC_ALL=en_US.utf8 ksh -c 'echo "${1//[0-9]}"' sh "$str"

 ٩ ۹ ߉ ९

이것이 곧 임박한 오류의 원인인 것 같습니다.

답변2

이는 숫자를 정의하는 방법에 따라 다릅니다. [0-9]종종 ASCII 숫자(또는 ASCII도 아니고 ASCII의 상위 집합도 아니지만 비트 표현만 다른 ASCII와 동일한 10자리 숫자일 수도 있습니다(EBCDIC)). ) ; \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

다음과 같은 경우가 아니더라도 해당 번호의 값을 얻기 위해 전화를 걸 수 있습니다 [0-9].

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

답변3

이론적 차이는 다른 답변에서 잘 설명되었으므로 여전히 설명이 필요합니다.실제차이점.

숫자 일치에 대한 보다 일반적인 사용 사례는 다음과 같습니다.


일회성 데이터 추출

일부 숫자를 처리하려고 할 때 숫자 자체가 어색한 형식의 텍스트 파일로 되어 있는 경우가 많습니다. 프로그램에서 사용하기 위해 추출하고 싶습니다. 파일을 보면 숫자 형식과 현재 로케일을 알 수 있으므로 다음과 같습니다.어떤 형태든 사용 가능, 작업이 완료되는 한.\d최소한의 키 입력이 필요하므로 매우 일반적으로 사용됩니다.

입력 정리

신뢰할 수 없는 사용자 입력(예: 웹 양식)이 있고 여기에 예상치 못한 내용이 포함되어 있지 않은지 확인해야 합니다. 데이터베이스의 숫자 필드에 저장하거나 서버에서 실행되는 셸 명령에 대한 인수로 사용하고 싶을 수도 있습니다. 이 경우 당신은 정말로 원합니다[0-9], 가장 제한적이고 예측 가능하기 때문입니다.

데이터 검증

"위험한" 용도로 사용하지 않을 일부 데이터가 있지만 그것이 숫자인지 아는 것이 좋을 것입니다. 예를 들어, 프로그램에서는 사용자가 주소를 입력할 수 있으며 입력 내용에 집 번호가 포함되어 있지 않은 경우 가능한 철자 오류를 강조 표시하려고 합니다. 이 경우에는 가능한 한 광범위하게 범위를 넓히고 싶을 것입니다.[[:digit:]]가는 길입니다.


이는 숫자 일치에 대한 가장 일반적인 세 ​​가지 사용 사례인 것 같습니다. 제가 중요한 내용을 놓쳤다고 생각하시면 댓글을 남겨주세요.

답변4

및 의 다른 의미는 [0-9]다른 답변에서 다룹니다. 여기에 정규식 엔진의 구현 차이점을 추가하고 싶습니다.[[:digit:]]\d

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

그래서[[:digit:]]항상 유효하다, \d의지하십시오. grep 매뉴얼에는 로케일에만 있다고 언급 되어 [[:digit:]]있습니다 .0-9C

PS1: 더 많은 정보를 알고 계시다면 표를 확장해 보세요.

PS2: GNU grep 3.1 및 GNU 4.4로 테스트되었습니다.

관련 정보