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.