Classifique não classificando linhas com um tubo '|' nele corretamente

17

Estou tentando classificar alguns dados simples delimitados por canal. No entanto, a classificação não é realmente uma classificação. Move a linha do meu cabeçalho para baixo, mas minhas duas linhas começando com 241 estão sendo divididas por uma linha começando com 24.

cat sort_fail.csv
column_a|column_b|column_c
241|212|20810378
24|121|2810172
241|213|20810376

sort sort_fail.csv
241|212|20810378
24|121|2810172
241|213|20810376
column_a|column_b|column_c

Os cabeçalhos das colunas estão sendo movidos para a parte inferior do arquivo, portanto, a classificação está claramente processando-o. Mas, os valores reais não estão sendo classificados como eu esperaria.

Nesse caso, trabalhei com ele

sort sort_fail.csv --field-separator='|' -k1,1

Mas sinto que isso não seria necessário. Por que a classificação não está classificada?

user10777668
fonte
2
use LC_COLLATE=C sort. Dependendo do que você está esperando, também pode ser necessárioLC_COLLATE=C sort -t'|' -n
mosvy
3
Para classificar os dados "estilo CSV" você pode querer usar csvsorta partir csvkit, que corretamente trata valores cotados.
Bakuriu 12/12/18

Respostas:

32

sort tem conhecimento do código do idioma, portanto, dependendo da sua configuração LC_COLLATE (herdada do LANG), você poderá obter resultados diferentes:

$ LANG=C sort sort_fail.csv 
241|212|20810378
241|213|20810376
24|121|2810172
column_a|column_b|column_c

$ LANG=en_US sort sort_fail.csv
241|212|20810378
24|121|2810172
241|213|20810376
column_a|column_b|column_c

Isso pode causar problemas nos scripts, porque você pode não estar ciente de como o local de chamada está definido e, portanto, pode obter resultados diferentes.

Não é incomum os scripts forçarem a configuração necessária

por exemplo

$ grep 'LC.*sort' /bin/precat
      LC_COLLATE=C sort -u | prezip-bin -z "$cmd: $2"

Agora, o interessante aqui é que o |personagem parece estranho.

Mas isso ocorre porque a regra padrão para en_US, que deriva da ISO, diz

$ grep 007C /usr/share/i18n/locales/iso14651_t1_common
<U007C> IGNORE;IGNORE;IGNORE;<j> # 142 |

O que significa que o |personagem é ignorado e a ordem de classificação seria como se o personagem não existisse.

$ tr -d '|' < sort_fail.csv | LANG=C sort
24121220810378
241212810172
24121320810376
column_acolumn_bcolumn_c

E isso corresponde à classificação "inesperada" que você está vendo.

As soluções alternativas são usar -n(para forçar classificações numéricas) ou usar o separador de campos (como você fez) ou usar o Ccódigo de idioma.

Stephen Harris
fonte
Fascinante. Eu vi alguns outros acertos sobre localização, mas achei que isso afetaria a ordem relativa de 24 vs 241, não algo assim.
user10777668
7
algo mais útil na classificação GNU é a --debugopção, que indica a chave (sublinhada) usada para comparar
Jeff Schaller
correr com --debug apenas sublinha a linha inteira - sort está incluindo o caractere de pipe, ele está definido para não ter impacto por causa da localização. É um bom recurso, mas não me ajudou nesse caso (eu tentei :) #
user10777668:
Foi exatamente por isso que mencionei, @ user10777668 - indica que sortestá usando a linha inteira em vez de parar nos caracteres que supomos que seja.
Jeff Schaller
Eu não esperava que isso parasse. Eu esperava que ele reconhecesse o caractere de pipe e o incluísse no tipo, tratando, portanto, 24 | 1 e 241 de maneira diferente. Não sei ao certo como --debug teria mudado isso e, de fato, dado que sublinha o | parece que ele teria distraído ativamente do verdadeiro problema onde a localização levou à caractere pipe sendo ingored
user10777668
1

O que me irrita é que o 24não se move do seu lugar entre os dois 241. O segundo campo começa com a 1. Tentando o tipo com uma liderança 4no segundo campo, o 24é movido para baixo, então suspeito que sortapenas ignore o |menos que seja dito o contrário. Tente sort -n...

RudiC
fonte
1

-n, --numeric-sort compara de acordo com o valor numérico da string

210
23

Sem o -n, 210 por texto está à frente de 23, pois vai caracterizar meu personagem.

michaelkrieger
fonte
Você está certo, mas isso não explica o caractere do cachimbo sendo diferente. As outras respostas mostram que, devido à localidade, o canal é tratado como não existente; portanto, o próximo dígito é o que decide a ordem.
Criggie