Especifique a ordem de classificação com LC_COLLATE, para que letras minúsculas estejam antes de letras maiúsculas

16

Dado o arquivo:

$ cat file
1
a
C
B
2
c
3
A
b

Por padrão, sortirá:

$ sort file
1
2
3
a
A
b
B
c
C

Com LC_COLLATE=Cisso, classificará em letras maiúsculas antes de minúsculas:

$ LC_COLLATE=C sort file
1
2
3
A
B
C
a
b
c

É possível obter uma classificação para reverter a ordem das maiúsculas e minúsculas, ou seja, dígitos, minúsculas e maiúsculas?

iiSeymour
fonte

Respostas:

8

Não conheço nenhum local que, por padrão, classifique nessa ordem. A solução é criar um código de idioma personalizado com uma ordem de classificação personalizada. Se alguém, quatro anos depois, quiser classificar de maneira personalizada, aqui está o truque.

A grande maioria dos códigos de idioma não especifica sua própria ordem de classificação, mas copia a ordem de classificação definida em, /usr/share/i18n/locales/iso14651_t1_commone é isso que você deseja editar. Em vez de alterar a ordem de classificação para quase todos os locais, modificando o original iso14651_t1_common, sugiro que você faça uma cópia. Detalhes sobre como a ordem de classificação funciona e como criar um código de idioma personalizado em seu $HOMEdiretório sem acesso root são encontrados nesta resposta a uma pergunta semelhante .

Veja como ae Asão ordenados com base em suas entradas em iso14651_t1_common:

<U0061> <a>;<BAS>;<MIN>;IGNORE # 198 a
<U0041> <a>;<BAS>;<CAP>;IGNORE # 517 A

be Bsão semelhantes:

<U0062> <b>;<BAS>;<MIN>;IGNORE # 233 b
<U0042> <b>;<BAS>;<CAP>;IGNORE # 550 B

Vemos que, na primeira passagem, ambos ae Atêm o símbolo de intercalação <a>, enquanto ambos be Btêm o símbolo de intercalação <b>. Desde <a>aparece antes <b>em iso14651_t1_common, ae Aestá empatado antes be B. A segunda passagem não quebra os empates porque todos os quatro caracteres têm o símbolo de intercalação <BAS>, mas durante a terceira passagem os empates são resolvidos porque o símbolo de intercalação para letras minúsculas <MIN>aparece na linha 3467, antes do símbolo de intercalação para letras maiúsculas <CAP>(linha 3488) . Assim, a ordem de classificação termina como a, A, b, B.

Trocar o primeiro e o terceiro símbolos de ordenação classificaria as letras primeiro por maiúsculas e minúsculas (mais baixo e mais alto), depois por sotaque ( <BAS>significa sem sotaque) e depois por ordem alfabética. No entanto , ambos <MIN>e <CAP>vêm antes dos dígitos numéricos, portanto, isso teria o efeito indesejado de colocar dígitos após as letras.

A maneira mais fácil de manter os dígitos primeiro e fazer todas as letras minúsculas aparecerem antes de todas as letras maiúsculas é forçar todas as letras a serem amarradas durante a primeira comparação, definindo todas iguais <a>. Para garantir que eles ordenem alfabeticamente dentro de maiúsculas e minúsculas, altere o último símbolo de intercalação de IGNOREpara o atual primeiro símbolo de intercalação. Seguindo esse padrão, aseria:

<U0061> <a>;<BAS>;<MIN>;<a> # 198 a

A se tornaria:

<U0041> <a>;<BAS>;<CAP>;<a> # 517 A

b se tornaria:

<U0062> <a>;<BAS>;<MIN>;<b> # 233 b

B se tornaria:

<U0042> <a>;<BAS>;<CAP>;<b> # 550 B

e assim por diante pelo resto das cartas.

Depois de criar uma versão personalizada iso14651_t1_common, siga as instruções na resposta vinculada acima para compilar seu código de idioma personalizado.

Molho de feijão
fonte
6

A configuração LC_COLLATE=Cnem sempre é suficiente para classificar maiúsculas e minúsculas. Pode ser necessário definir LC_ALL=C.

Isso também levará em consideração caracteres não alfanuméricos e até imprimíveis, mas se você não quiser que haja opções -de -i(descrito em man sort) desativará isso.

Provavelmente, falhará mal com a entrada multibyte, como UTF-8 com caracteres não ASCII.

Para obter letras minúsculas (em ordem) antes de maiúsculas (em ordem), a melhor maneira de pensar que não envolve a quebra de uma linguagem de programação completa é inverter o caso de todas as letras antes da classificação e invertê-las de volta mais tarde.

tr 'a-zA-Z' 'A-Za-z' < file | LC_ALL=C sort | tr 'a-zA-Z' 'A-Za-z'
Lei29
fonte
2

Não sou especialista, mas nunca vi um código de idioma que defina agrupamento como esse. AFAIK esse agrupamento é apenas em C, onde é baseado em valores ASCII . (Normalmente, eu resolveria isso apenas por um script.)

No entanto, nunca fiz isso, mas convém consultar as páginas de manual localedef (1) e locale (5) para entender como os locais são definidos e, eventualmente, definir o seu próprio.

Além disso, não esqueça que, se houver caracteres diacríticos ou especiais, o código de idioma C não os tratará como você deseja. Por exemplo, ele não será colocado ápróximo aou Łpróximo L. Nesses casos, a localidade nativa do idioma seria provavelmente um melhor ponto de partida.

Alois Mahdal
fonte
0

Acredito que a resposta é sem precisar LC_COLLATE alterado (ou seja, deixar a função como comportamento padrão):

arquivo sort -f

Isso funciona no Linux; consulte a seção de ajuda para obter o comando, caso você esteja no Unix e esteja executando uma versão diferente. -f é definido como caso a ignorar.

Obrigado pela correção rápida (e estranhamente) e edição da gramática fora de lugar, Stephen Rauch.

1m.0g
fonte
-1
LC_COLLATE="en_US.UTF-8" sort file
unxnut
fonte
Isso não classifica em minúsculas antes de maiúsculas? ideone.com/Gtyg4Z
iiSeymour
Hmm, no meu caso, foi usando o seu exemplo.
Unxnut
4
@unxnut Isso está incorreto. Sem o ponto e vírgula, o comando definiria o ambiente para sort, mas com o ponto e vírgula a variável é local para o shell e não afeta o comportamento de sort. O ponto e vírgula pode ser mantido como se a variável também fosse exportada, mas isso também afetaria outros comandos.
Anders Sjöqvist