Como classificar linhas com dois colchetes angulares?

4

Parece que sort se comporta de maneira estranha em linhas como >>b

$ cat test
a
>>b
b
c
>
>>

$ sort test
>
>>
a
b
>>b
c

Espero que a linha >>b seja a terceira saída em sort , mas é a quinta. Por que isso acontece e existe uma maneira de fazer com que sort dê a saída esperada?

Estou usando o GNU / Linux Ubuntu 16.04.

    
por Nathan Wilson 16.11.2016 / 22:31

2 respostas

7

Os algoritmos de ordenação nos locais modernos são bastante complexos.

Cada caractere (na verdade, elemento de agrupamento que pode consistir em uma sequência de vários caracteres como o tcheco ch ) recebe um número de pesos de agrupamento que decidem ordem de classificação.

Ao comparar duas strings, o primeiro peso de todos os caracteres é usado primeiro, e outros pesos são usados posteriormente para decidir os laços se as duas strings forem ordenadas da mesma forma com os primeiros pesos.

Por exemplo, em muitos locais, e , é e E têm o mesmo peso primário (eles são da mesma classe de equivalência, todos correspondem a [=e=] ).

Portanto, ao comparar, por exemplo, echo , été e Enter , na primeira passagem, e , é e E tendo o mesmo peso primário, é o segundo caractere que determinará o pedido ( c antes de n antes de t ).

Ao comparar été , Été , Ete , após a primeira passagem, todos eles são classificados da mesma forma, então usamos a segunda passagem usando o peso secundário. Em locais típicos do GNU, o segundo peso para caracteres de escrita latina é usado para priorizar os acentos (nenhum acento aparece primeiro, depois agudo, grave, breve, circunflexo ...). Em seguida, precisaremos usar o terceiro peso para decidir entre été e Été e isso será baseado no caso (minúsculas primeiro na maioria dos locais). Existem até personagens que acabam classificando o mesmo porque todos os seus pesos são idênticos.

Isso é usado para classificar o texto de maneira similar aos dicionários, como um humano faria.

Em um dicionário, você descobrirá que o espaço e a maioria dos caracteres de pontuação também são ignorados. Por exemplo, de facto classifica entre debut e devoid . O primeiro peso do caractere de espaço é IGNORE.

Em um sistema GNU, você encontrará as regras de intercalação principais definidas no /usr/share/i18n/locales/iso14651_t1_common (o caminho pode variar com a distribuição). Lá você verá:

ifdef UPPERCASE_FIRST
<CAP>
else
<MIN>
endif
[...]
ifdef UPPERCASE_FIRST
[...]
<MIN> # 10
[...]
else
[...]
<CAP> # 9
[...]
endif

[...]
order_start <SPECIAL>;forward;backward;forward;forward,position
<U0020> IGNORE;IGNORE;IGNORE;<U0020> # 32 <SP>
[...]
<U003E> IGNORE;IGNORE;IGNORE;<h> # 140 >
[...]
ifdef DIACRIT_FORWARD
order_start <LATIN>;forward;forward;forward;forward,position
else
order_start <LATIN>;forward;backward;forward;forward,position
endif
[...]
<U0065> <e>;<BAS>;<MIN>;IGNORE # 259 e
<U00E9> <e>;<ACA>;<MIN>;IGNORE # 260 é
[...]
<U0045> <e>;<BAS>;<CAP>;IGNORE # 577 E
<U00C9> <e>;<ACA>;<CAP>;IGNORE # 578 É

Que ilustram o que acabamos de dizer. O espaço e > têm seus primeiros 3 pesos definidos como IGNORE . É apenas para as strings classificarem as mesmas para as 3 primeiras ponderações que sua ordem relativa será considerada ( > antes do espaço, conforme a <h> listaria antes do símbolo de classificação não especificado <U0020> ).

Nas localidades que definem UPPERCASE_FIRST (como /usr/share/i18n/locales/tr_TR ), as letras maiúsculas virão primeiro (na passagem 3 rd ). Mesmo com DIACRIT_FORWARD , onde algumas localidades como de_DE podem decidir reverter a ordem dos diacríticos para a passagem de 2 nd .

> e >> ordenam o mesmo na passagem 1 st , 2 nd e 3 rd . No 4 th , > ordena antes de >> à medida que a string vazia é classificada antes de tudo.

>>b classifica após b porque eles ordenam o mesmo nas primeiras 3 passagens, mas na quarta passagem, b é IGNORE, então > é maior. É menor que c na primeira passagem ( > ignorado e b antes c ) ... Você entendeu.

Agora, se você observar a definição C locale. É muito mais simples. Há apenas um peso, e o peso é baseado no valor do ponto no código de U + 0000 para U + 10FFFF. Portanto, SPC (U + 0020) classifica antes de > (U + 003E), que classifica antes de b (U + 0062) que classifica antes de c (U + 0063). Nenhum personagem é ignorado.

Note que com o GNU libc, pelo menos, essa ordem definida no arquivo de definição de código de idioma C é ignorada quando se trata de funções de comparação ( strcoll() e co. como usado por sort ). Independentemente do valor de LC_CTYPE , com LC_COLLATE=C , strcoll() é equivalente a strcmp() . Como na comparação está sempre no valor de byte, mesmo que esses bytes correspondam a caracteres cujo ponto de código unicode faça o contrário (como 0xA4 U + 20AC EURO SIGN vs A5 U + 00A5 YEN SIGN no conjunto de caracteres ISO-8859-15) , então LC_ALL=C sort e LC_COLLATE=C sort (desde que LC_ALL não esteja definido de outra forma) terão o mesmo efeito lá.

    
por 16.11.2016 / 23:42
1

Na página sort(1) man:

   *** WARNING *** The locale specified by the  environment  affects  sort  order.   Set
   LC_ALL=C to get the traditional sort order that uses native byte values.

Para classificar por valor de byte, use:

LC_ALL=C sort test

Caso contrário, sort ignorará os caracteres principais até encontrar uma chave pela qual possa classificar, e é por isso que >>b e b ficam adjacentes.

    
por 16.11.2016 / 22:43

Tags