A ordem de intercalaçãoLC_COLLATE
define não apenas a ordem de classificação de caracteres individuais, mas também o significado dos intervalos de caracteres. Ou faz? Considere o seguinte snippet:
unset LANGUAGE LC_ALL
echo B | LC_COLLATE=en_US grep '[a-z]'
Intuitivamente, B
não está presente [a-z]
, portanto, isso não deve gerar nada. É o que acontece no Ubuntu 8.04 ou 10.04. Mas em algumas máquinas rodando Debian Lenny ou aperto, B
é encontrado, porque a gama a-z
inclui tudo o que está entre a
e z
na ordem de agrupamento, incluindo as letras maiúsculas B
através Z
.
Todos os sistemas testados têm o en_US
código do idioma gerado. Também tentei variar o código do idioma: nas máquinas com as B
correspondências acima, o mesmo acontece em todos os códigos de idioma disponíveis (principalmente com base em latim: {en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}
também códigos de idioma chinês), exceto no japonês (em qualquer codificação disponível) e C
/ POSIX
.
O que significam intervalos de caracteres em expressões regulares quando você ultrapassa o ASCII? Por que existe uma diferença entre algumas instalações Debian, por um lado, e outras instalações Debian e Ubuntu, por outro? Como se comportam outros sistemas? Quem está certo e contra quem um bug deve ser relatado?
(Observe que estou perguntando especificamente sobre o comportamento dos intervalos de caracteres, como [a-z]
nas en_US
localidades, principalmente nos sistemas baseados em GNU libc. Não estou perguntando como combinar letras minúsculas ou letras minúsculas ASCII.)
Em duas máquinas Debian, uma onde B
está [a-z]
e outra onde não está, a saída de LC_COLLATE=en_US locale -k LC_COLLATE
é
collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=1
collate-codeset="ISO-8859-1"
e a saída de LC_COLLATE=en_US.utf8 locale -k LC_COLLATE
é
collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"
fonte
en_US
Porém, não verificou se é gerado.C
idioma será usado como substituto, e sua ordem de intercalação será de valores de bytes diretos, portantoB
, não será correspondida. Teste em um código de idioma que aparece na saída delocale -a
.Respostas:
Se você estiver usando algo diferente do
C
código do idioma, não deverá usar intervalos como,[a-z]
pois eles dependem do código do idioma e nem sempre fornecem os resultados esperados. Além do problema de caso que você já encontrou, algumas localidades tratam caracteres com sinais diacríticos (por exemplo, á ) da mesma forma que o caractere base ( por exemplo, a ).Em vez disso, use uma classe de caracteres nomeada:
Isso sempre dará o resultado correto para o código do idioma. No entanto, você precisa escolher o local para refletir o significado do texto de entrada e do teste que você está tentando aplicar.
Por exemplo, se você precisar encontrar um valor de byte específico, use o
C
código do idioma, que está sempre disponível:Se isso não funcionar como esperado, é realmente um bug.
fonte
locale -k
à minha pergunta; é idêntico em duas máquinas Debian, uma ondeB
está no intervalo e outra onde não está. BTW eu não sou root em nenhuma máquina (então não é algo peculiar que eu faço como administrador).echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'
retornaa
ANDü
enquantoecho "Baü" | LC_COLLATE=C grep -o '[a-z]'
retorna apenasa
. A meu ver, "inferior" não é realmente o que o OP queria #C
local. Acredito que isso seja relevante para o OP, que estava procurando relatar um bug. Se você não estiver noC
local, os resultados do uso de intervalos são altamente imprevisíveis e, portanto, nunca podem ser considerados um bug. Por outro lado, se você precisar encontrar um valor de byte específico, use oC
código do idioma. Meu ponto secundário foi que, se você realmente deseja procurar letras minúsculas em um código de idioma, use uma classe de caracteres. Embora o OP possa não estar procurando isso, outros poderão encontrar essa pergunta.Intervalos em expressões regulares devem observar a configuração de agrupamento. Aqui está o padrão relevante: http://pubs.opengroup.org/onlinepubs/007908799/xbd/re.html (procure por "expressões de intervalo"). Portanto,
echo B | LC_COLLATE=en_US grep '[a-z]'
deve serB
fornecida uma definição sensata do respectivo código do idioma. Não sei explicar por que isso às vezes não funciona para você, mas ficaria muito surpreso se encontrasse isso em um sistema não antigo que esteja instalado e configurado corretamente.fonte
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]'
Não imprime nada no Ubuntu 12.04 com grep 2.10. Não imprime nada no Centos 6.5 com grep 2.6.3. Funciona no Debian 6.0.8 com grep 2.6.3.