LC_COLLATE가 문자 범위에 영향을 미칩니 까?


27

데이터 정렬 을 통해 순서 LC_COLLATE를 정의 개별 문자의 정렬 순서뿐만 아니라 문자 범위의 의미뿐만 아닙니다. 아니면? 다음 스 니펫을 고려하십시오.

unset LANGUAGE LC_ALL
echo B | LC_COLLATE=en_US grep '[a-z]'

직관적으로에 B있지 않으므로 [a-z]아무것도 출력하지 않아야합니다. 그것이 우분투 8.04 또는 10.04에서 일어나는 일입니다. 그러나 데비안 레니 또는 스퀴즈를 실행하는 일부 시스템에서, B범위가 있기 때문에, 발견 a-z사이의 모든 것을 포함 a하고 z대문자를 포함하여 조합 순서에 B통해를 Z.

테스트 된 모든 시스템에는 en_US로케일이 생성됩니다. 또한 로케일을 변경하려고 시도했습니다. B위와 일치 하는 시스템에서 {en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}일본어 (사용 가능한 인코딩) 및 C/를 제외한 모든 사용 가능한 로케일 (대부분 라틴어 기반 : 중국어 로케일)에서도 동일하게 발생 합니다 POSIX.

ASCII를 넘어 서면 정규 표현식에서 문자 범위의 의미는 무엇입니까 ? 한편으로 일부 데비안 설치와 다른 데비안 설치와 우분투가 다른 이유는 무엇입니까? 다른 시스템은 어떻게 작동합니까? 누가 옳고 누가 버그를보고해야합니까?

로케일, 주로 GNU libc 기반 시스템 [a-z]에서 와 같은 문자 범위의 동작에 대해 구체적으로 묻습니다 en_US. 소문자 또는 ASCII 소문자를 일치시키는 방법을 묻지는 않습니다.


두 데비안 기계, 하나 B[a-z]그렇지 않은 하나의 출력 LC_COLLATE=en_US locale -k LC_COLLATEIS

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=1
collate-codeset="ISO-8859-1"

그리고 출력 LC_COLLATE=en_US.utf8 locale -k LC_COLLATE

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"

1
내가 사용했던 데비안 레니 인스턴스를 재현하지 못합니다. en_US그래도 생성 되었는지 확인하지 않았습니다 .
alex

1
@alex 로케일이 생성되지 않으면 C로케일이 폴백으로 사용되며 데이터 정렬 순서는 스트레이트 바이트 값이므로 B일치하지 않습니다. 의 출력에 나타나는 로케일에서 테스트하십시오 locale -a.
Gilles 'SO- 악한 중지'

1
en_US는 en_US.utf8과 동일하지 않으며 설치 한 항목에 따라 en_US.iso-8859-1을 의미합니다. en_US (접미사가없는)가 locale -a의 출력에 나타나지 않으면 실제로이 로케일이없는 것입니다. LC_COLLATE = en_US locale -k LC_COLLATE는 무엇을 표시합니까?
Neil Mayhew

1
이것은 이론적 인 질문이 아닌 실용적인 질문으로 밝혀졌습니다. 왜 awk 정규식에서 대문자가 다양한 소문자로 포함됩니까?
Caleb

1
@isaac 불행하게도, 7 년 후, 나는 문제가있는 시스템에 접근 할 수없는 것 같습니다. 그들은 모두 업그레이드 또는 해체되었습니다.
Gilles 'SO- 악마 그만해

답변:


3

C로케일 이외의 다른 것을 사용하는 경우 , [a-z]로케일에 따라 다르며 항상 예상 한 결과를 제공하지는 않으므로 같은 범위를 사용해서는 안됩니다 . 이미 발생한 사례 문제뿐만 아니라 일부 로케일은 분음 부호가있는 문자 (예 : á )를 기본 문자 (예 : a ) 와 동일하게 취급합니다 .

대신 명명 된 문자 클래스를 사용하십시오.

echo B | grep '[[:lower:]]'

이것은 항상 로케일에 대한 올바른 결과를 제공합니다. 그러나 입력 텍스트와 적용하려는 테스트의 의미를 반영하려면 로캘을 선택해야합니다.

예를 들어 특정 바이트 값을 찾아야하는 경우 C항상 사용할 수 있는 로캘을 사용하십시오 .

echo B | LANG=C grep '[a-z]'

이것이 예상대로 작동하지 않으면 실제로 버그입니다.


나는 그것이 내가 요구 한 것이 아니라는 것을 안다. 명시 적 범위가 무엇을 의미하는지, 왜 GNU libc 및 GNU grep을 사용하여 다른 배포판이 다른 동작을하는지에 대해 구체적으로 묻습니다. (여러분의 말이 정확하기는하지만, 관련이 없습니다.)
Gilles 'SO-Stop

1
내 요점은 명시 적 범위의 의미는 로케일에 따라 다르며 다른 시스템은 로케일을 동일한 방식으로 정의 할 필요가 없으므로 버그가 아닙니다. 기술적으로는 시스템을 남용하고 있으므로 "정의되지 않은"동작에 놀라지 않아야합니다. 또한, 몇몇 사람들은 데비안 시스템에서 동작을 재현 할 수 없다고 언급 했으므로 시스템에 이상한 점이있는 것 같습니다.
Neil Mayhew

1
범위의 동작은 로캘에 따라 다릅니다. 나는 Glibc를 사용하는 다른 시스템 (그리고 같은 데비안 릴리스의 다른 설치조차도)이 다른 행동을하는 방법을 묻고 놀랐습니다. locale -k내 질문에 대한 결과를 추가했습니다 . 두 개의 데비안 머신에서 동일합니다. 하나 B는 범위 안에 있고 다른 하나는 그렇지 않습니다. BTW 나는 어느 컴퓨터에서든 루트가 아닙니다 (따라서 관리자로서 독특하지 않습니다).
Gilles 'SO- 악마 그만해'

echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'반환 aü동안의 echo "Baü" | LC_COLLATE=C grep -o '[a-z]'만 반환합니다 a. 내 눈에, "낮은"를 OP 원하는 것을 정말 아니다
다니엘 알더

내 원래 요점은 여전히 ​​설명합니다 : C로케일 에 있지 않으면 범위를 사용하지 마십시오 . 버그를 신고하려는 OP와 관련이 있다고 생각합니다. C로케일 이 아닌 경우 범위를 사용한 결과는 예측할 수 없으므로 버그로 간주 될 수 없습니다. 반면에 특정 바이트 값을 찾아야하는 경우 C로케일을 사용하십시오 . 두 번째 요점은 로케일에서 소문자를 실제로 검색하려면 문자 클래스를 사용한다는 것입니다. OP가 이것을 찾지 못했을 수도 있지만 다른 사람들이이 질문을 찾은 경우가 있습니다.
Neil Mayhew

1

정규식의 범위는 데이터 정렬 설정을 준수해야합니다. 관련 표준은 다음과 같습니다. http://pubs.opengroup.org/onlinepubs/007908799/xbd/re.html ( "범위 표현식"을 찾으십시오). 따라서 해당 로케일에 대한 적절한 정의가 제공 echo B | LC_COLLATE=en_US grep '[a-z]'되어야합니다 B. 왜 이것이 당신에게 효과가 없는지 설명 할 수는 없지만, 제대로 설치되고 구성된 비 고대 시스템에서이 문제가 발생하면 매우 놀랍습니다.


1
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]' grep 2.10으로 Ubuntu 12.04에서 아무것도 인쇄하지 않습니다. grep 2.6.3을 사용하여 Centos 6.5에서 아무 것도 인쇄하지 않습니다. grep 2.6.3과 함께 Debian 6.0.8에서 작동합니다.
Ian D. Allen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.