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

11

Dado o arquivo:

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

Por padrão, sort será:

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

Com LC_COLLATE=C , por isso, irá ordenar 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 ordenação para reverter a ordenação de casos, ou seja, dígitos, letras minúsculas e maiúsculas?

    
por iiSeymour 10.05.2013 / 13:49

5 respostas

6

Não sei de nenhuma localidade que, por padrão, classifique nessa ordem. A solução é criar uma localidade personalizada com uma ordem de classificação personalizada. Se alguém, quatro anos depois, quiser classificar de forma personalizada, aqui está o truque.

A grande maioria das localidades 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_common , então é isso que você deseja editar. Em vez de alterar a ordem de classificação para quase todas as localidades, 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 uma localidade personalizada no diretório $HOME sem acesso à raiz são encontrados nesta resposta a uma pergunta semelhante .

Veja como a e A sã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

b e B são semelhantes:

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

Vemos que na primeira passagem, tanto a como A têm o símbolo de intercalação <a> , enquanto que b e B têm o símbolo de intercalação <b> . Como <a> aparece antes de <b> em iso14651_t1_common , a e A são vinculados antes de b e B . A segunda passagem não quebra os empates porque todos os quatro caracteres têm o símbolo de agrupamento <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 letras maiúsculas <CAP> (linha 3488). Assim, a ordem de classificação acaba em a , A , b , B .

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

A maneira mais fácil de manter os dígitos antes de fazer todas letras minúsculas virem antes todas letras maiúsculas é forçar todas as letras a se ligarem durante a primeira comparação, definindo-as todas iguais codificar%. Para certificar-se de que eles estejam ordenados alfabeticamente no caso, altere o último símbolo de intercalação de <a> para o primeiro símbolo de intercalação atual. Seguindo esse padrão, IGNORE se tornaria:

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

a se tornaria:

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

A se tornaria:

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

b se tornaria:

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

e assim por diante para o resto das letras.

Depois de criar uma versão personalizada de B , siga as instruções em a resposta acima para compilar sua localidade personalizada.

    
por 24.04.2017 / 20:11
4

A configuração de LC_COLLATE=C nem sempre é suficiente para classificar maiúsculas antes de minúsculas. Você pode precisar definir LC_ALL=C .

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

Ele provavelmente irá falhar com a entrada multibyte, como UTF-8 com caracteres não-ASCII.

Para ficar em minúsculas (em ordem) antes de maiúsculas (em ordem), a melhor maneira que posso pensar que não envolve quebrar uma linguagem de programação completa é inverter o caso de todas as letras antes do tipo, e invertendo-os de volta depois.

tr 'a-zA-Z' 'A-Za-z' < file | LC_ALL=C sort | tr 'a-zA-Z' 'A-Za-z'
    
por 08.07.2016 / 16:08
2

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

No entanto, eu nunca fiz isso, mas você pode querer olhar para localedef (1) e locale (5) manpages para obter uma compreensão de como as localidades são definidas e eventualmente defina seu próprio.

Além disso, não se esqueça de que, se houver sinais diacríticos ou caracteres especiais, a localidade C não os tratará como você deseja. Por exemplo, não colocará á perto de a ou Ł near L . Nesses casos, a localidade nativa da linguagem provavelmente seria um ponto de partida melhor.

    
por 10.05.2013 / 14:18
0
LC_COLLATE="en_US.UTF-8"; sort file
    
por 10.05.2013 / 17:33
0

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

classificar -f arquivo

Isso funciona no Linux; por favor consulte a sua seção de ajuda para o comando caso você esteja no Unix e executando uma versão diferente. -f é definido como ignorando maiúsculas e minúsculas.

Obrigado pela correção rápida (e estranha) e edite a gramática equivocada, Stephen Rauch.

    
por 26.05.2017 / 03:25

Tags