Python classifica por valor de byte por padrão, o que significa que é vem depois de z e outras coisas igualmente engraçadas. Qual é a melhor maneira de classificar alfabeticamente em Python?
Existe uma biblioteca para isso? Não consegui encontrar nada. De preferência, a classificação deve ter suporte de idioma para que entenda que åäö deve ser classificado após z em sueco, mas que ü deve ser classificado por u etc. O suporte Unicode é, portanto, praticamente um requisito.
Se não houver biblioteca para isso, qual é a melhor maneira de fazer isso? Basta fazer um mapeamento de letra para um valor inteiro e mapear a string para uma lista de inteiros com isso?
locale.strcoll
resposta está correta quando você precisa da classificação Unicode usando a localidade do usuário, e o ICU responde o que você deseja quando você precisa de mais do que isso (agrupamento usando mais de uma localidade). Na maioria das vezes, você querlocale.strcoll
.locale.strcoll
funciona e principalmente o que o ICU faz melhor do que a função Python. Basicamente, mais atenção para a pergunta.--locale=de__phonebook
quando você precisa. O módulo Perl passa no conjunto de testes do UCA, e o script que forneci torna muito mais fácil jogar com todo o UCA, além de todas as suas opções, incluindo locais, apenas a partir da linha de comando. Pode não responder à pergunta, mas ainda assim deve ser muito interessante. Se você estiver na Suíça, tenho certeza de que precisa de flexibilidade. :)Respostas:
A biblioteca ICU da IBM faz isso (e muito mais). Possui ligações Python: PyICU .
Atualização : A principal diferença na classificação entre ICU e
locale.strcoll
é que ICU usa o algoritmo de agrupamento Unicode completo enquantostrcoll
usa ISO 14651 .As diferenças entre esses dois algoritmos são resumidas brevemente aqui: http://unicode.org/faq/collation.html#13 . Esses são casos especiais bastante exóticos, que raramente deveriam importar na prática.
fonte
locale.strxfrm
a resposta de u0b34a0f6ae e parece funcionar e é muito mais elegante e não requer nenhum software adicional.sudo pip3 install PyICU
falha na instalação e também para Python2.Eu não vejo isso nas respostas. Meu aplicativo classifica de acordo com a localidade usando a biblioteca padrão do python. É muito fácil.
Pergunta para Lennart e outros respondentes: Alguém sabe 'local' ou não cabe a essa tarefa?
fonte
Experimente o algoritmo de agrupamento Python Unicode de James Tauber . Pode não funcionar exatamente como você deseja, mas vale a pena dar uma olhada. Para mais informações sobre os problemas, veja esta postagem de Christopher Lenz.
fonte
Você também pode estar interessado em pyuca :
http://jtauber.com/blog/2006/01/27/python_unicode_collation_algorithm/
Embora certamente não seja a maneira mais exata, é uma maneira muito simples de pelo menos acertar um pouco. Ele também supera a localidade em um webapp, pois a localidade não é threadsafe e define as configurações de idioma em todo o processo. Também é mais fácil de configurar do que o PyICU, que depende de uma biblioteca C externa.
Eu carreguei o script para o github porque o original estava fora do ar no momento em que este livro foi escrito e tive que recorrer a caches da web para obtê-lo:
https://github.com/href/Python-Unicode-Collation-Algorithm
Eu usei com sucesso este script para classificar corretamente o texto Alemão / Francês / Italiano em um módulo do Plone.
fonte
Um resumo e uma resposta ampliada:
locale.strcoll
no Python 2, e delocale.strxfrm
fato resolverá o problema e fará um bom trabalho, supondo que você tenha o local em questão instalado. Eu testei no Windows também, onde os nomes das localidades são confusamente diferentes, mas por outro lado, parece que todas as localidades com suporte estão instaladas por padrão.ICU
não necessariamente faz isso melhor na prática, no entanto, faz muito mais . Mais notavelmente, possui suporte para divisores que podem dividir textos em diferentes idiomas em palavras. Isso é muito útil para idiomas que não possuem separadores de palavras. Você precisará ter um corpus de palavras para usar como base para a divisão, porque isso não está incluído, no entanto.Ele também tem nomes longos para os locais para que você possa obter nomes de exibição bonitos para o local, suporte para outros calendários além do Gregoriano (embora eu não tenha certeza de que a interface Python suporte isso) e toneladas e toneladas de outros suportes de localidade mais ou menos obscuros .
Resumindo: se você deseja classificar em ordem alfabética e de acordo com a localidade, pode usar o
locale
módulo, a menos que tenha requisitos especiais ou também precise de mais funcionalidade dependente da localidade, como divisor de palavras.fonte
Vejo que as respostas já fizeram um excelente trabalho, só queria apontar uma ineficiência de codificação no Human Sort . Para aplicar uma tradução seletiva caractere por caractere a uma string unicode s, ele usa o código:
Python tem uma maneira muito melhor, mais rápida e mais concisa de realizar esta tarefa auxiliar (em strings Unicode - o método análogo para strings de byte tem uma especificação diferente e um pouco menos útil! -):
O dict que você passa para o
translate
método tem ordinais Unicode (não strings) como chaves, e é por isso que precisamos dessa etapa de reconstrução do char-para-char originalspec_dict
. (Os valores no dicionário que você passa para traduzir [em oposição às chaves, que devem ser ordinais] podem ser ordinais Unicode, strings Unicode arbitrárias ou Nenhum para remover o caractere correspondente como parte da tradução, por isso é fácil especificar "ignorar um determinado caractere para fins de classificação "," mapear ä para ae para fins de classificação "e semelhantes).No Python 3, você pode obter a etapa de "reconstrução" de forma mais simples, por exemplo:
Consulte a documentação para outras maneiras de usar esse
maketrans
método estático no Python 3.fonte
Para implementá-lo, você precisará ler sobre o "algoritmo de agrupamento Unicode", consulte http://en.wikipedia.org/wiki/Unicode_collation_algorithm
http://www.unicode.org/unicode/reports/tr10/
um exemplo de implementação está aqui
http://jtauber.com/blog/2006/01/27/python_unicode_collation_algorithm/
fonte
Ultimamente, tenho usado zope.ucol ( https://pypi.python.org/pypi/zope.ucol ) para esta tarefa. Por exemplo, classificando o alemão ß:
zope.ucol também envolve a UTI, então seria uma alternativa para a PyICU.
fonte
Uma solução UCA completa
A maneira mais simples, fácil e direta de fazer isso é fazer um callout para o módulo da biblioteca Perl, Unicode :: Collate :: Locale , que é uma subclasse do módulo Unicode :: Collate padrão . Tudo o que você precisa fazer é passar ao construtor um valor de localidade
"xv"
para Suécia.(Você pode não necessariamente apreciar isso para texto em sueco, mas como Perl usa caracteres abstratos, você pode usar qualquer ponto de código Unicode que quiser - não importa a plataforma ou compilação! Poucos idiomas oferecem essa conveniência. Menciono isso porque estou lutando contra um perdendo muito a batalha com o Java por causa desse problema enlouquecedor ultimamente.)
O problema é que não sei como acessar um módulo Perl do Python - exceto, isto é, usando um callout shell ou um pipe de dois lados. Para esse fim, forneci a você um script de trabalho completo chamado ucsort, que você pode chamar para fazer exatamente o que pediu com perfeita facilidade.
Este script é 100% compatível com o Unicode Collation Algorithm completo , com todas as opções de personalização suportadas !! E se você tiver um módulo opcional instalado ou executar Perl 5.13 ou superior, terá acesso total aos locais CLDR fáceis de usar. Ver abaixo.
Demonstração
Imagine um conjunto de entrada ordenado desta forma:
Uma classificação padrão por ponto de código produz:
o que está incorreto no livro de todos. Usando meu script, que usa o algoritmo de agrupamento Unicode, você obtém esta ordem:
Essa é a classificação UCA padrão. Para obter a localidade sueca, chame ucsort desta forma:
Aqui está uma demonstração de entrada melhor. Primeiro, o conjunto de entrada:
Por ponto de código, isso classifica desta forma:
Mas usar o UCA padrão faz com que seja classificado da seguinte maneira:
Mas na localidade sueca, desta forma:
Se você preferir letras maiúsculas antes de letras minúsculas, faça o seguinte:
Ordenações Personalizadas
Você pode fazer muitas outras coisas com o ucsort . Por exemplo, aqui está como classificar títulos em inglês:
Você precisará do Perl 5.10.1 ou superior para executar o script em geral. Para suporte local, você deve instalar o módulo CPAN opcional
Unicode::Collate::Locale
. Como alternativa, você pode instalar uma versão de desenvolvimento do Perl, 5.13+, que inclui esse módulo padrão.Convenções de chamada
Este é um protótipo rápido, então ucsort está quase totalmente sub (der) documentado. Mas este é o seu SINOPSE de quais interruptores / opções ele aceita na linha de comando:
Sim, ok: essa é realmente a lista de argumentos que uso para a chamada para
Getopt::Long
, mas essa é a ideia. :)Se você puder descobrir como chamar os módulos da biblioteca Perl diretamente do Python sem chamar um script Perl, faça-o com certeza. Eu só não sei como. Adoraria aprender como.
Nesse ínterim, acredito que este script fará o que você precisa em todas as suas particularidades - e muito mais! Agora eu uso isso para toda a classificação de texto. Ele finalmente faz o que eu precisava de um longo, longo tempo.
A única desvantagem é que o
--locale
argumento faz com que o desempenho diminua, embora seja rápido o suficiente para classificação normal, não local, mas ainda 100% compatível com UCA . Uma vez que carrega tudo na memória, você provavelmente não deseja usar isso em documentos gigabyte. Eu o uso várias vezes ao dia, e com certeza é ótimo ter finalmente uma classificação sensata de texto.fonte
Ele está longe de ser uma solução completa para seu caso de uso, mas você pode dar uma olhada no script unaccent.py de effbot.org. O que basicamente faz é remover todos os acentos de um texto. Você pode usar esse texto 'higienizado' para classificar em ordem alfabética. (Para uma descrição melhor, consulte esta página.)
fonte
Jeff Atwood escreveu um bom post sobre Ordem de Classificação Natural , nele vinculou a um script que faz praticamente o que você pede .
Não é um script trivial, de forma alguma, mas funciona.
fonte