파이썬에서 알파벳순으로 유니 코드 문자열을 정렬하는 방법은 무엇입니까?


97

파이썬은 기본적으로 바이트 값을 기준으로 정렬합니다. 즉, é는 z 뒤에 오는 다른 똑같이 재미있는 것들입니다. Python에서 알파벳순으로 정렬하는 가장 좋은 방법은 무엇입니까?

이것에 대한 도서관이 있습니까? 나는 아무것도 찾을 수 없었다. 선호하는 정렬은 언어 지원이 있어야 åäö가 스웨덴어로 z 다음에 정렬되어야하지만 ü는 u 등으로 정렬되어야한다는 것을 이해합니다. 따라서 유니 코드 지원은 거의 필수 요건입니다.

라이브러리가없는 경우이를 수행하는 가장 좋은 방법은 무엇입니까? 문자에서 정수 값으로 매핑하고 문자열을 정수 목록에 매핑하십시오.


11
이는 훨씬 더 많은 로케일에 따라 다릅니다. 스웨덴어에서는 "Ä"가 "Z"뒤에오고 있지만 독일어에서는 "Ä"가 일반적으로 "AE"로 정렬됩니다.
balpha

@Georg : 이것에 대해 현상금을 연 이유가 있었나요? locale.strcoll대답은 유니 코드가 사용자의 로케일을 사용하여 정렬을 필요로 할 때 정확하고, 더보다 (두 개 이상의 로케일을 사용하여 정렬)을 필요로 할 때 당신이 원하는 무엇 ICU 대답. 대부분의 경우 locale.strcoll.
Glenn Maynard

@Glenn : 저는 얼마나 잘 locale.strcoll작동하는지, 특히 ICU 가 파이썬 함수보다 더 잘하는 것을 알고 싶었습니다 . 기본적으로 질문에 대한 더 많은 관심이 있습니다.
Georg Schölly

1
@Georg : 내 대답에서 볼 수 있듯이 최근 Unicode Collation Algorithm을 많이 사용했습니다. 예를 들어 --locale=de__phonebook필요할 때 정렬 할 수 있다는 것은 정말 훌륭 합니다. Perl 모듈은 UCA 테스트 스위트를 통과하고 제가 제공 한 스크립트 를 사용하면 명령 줄에서 전체 UCA와 로케일포함한 모든 옵션 훨씬 쉽게 플레이 할 수 있습니다 . 대답하지 않을 수 있습니다 질문을하지만, 그것은 여전히 매우 흥미 있어야한다. 스위스에 계시다면 유연성을 사용할 수있을 것입니다. :)
tchrist

답변:


75

IBM의 ICU 라이브러리가이를 수행합니다. Python 바인딩이 있습니다 : PyICU .

업데이트 : ICU와 ICU 정렬의 핵심 차이점은 locale.strcollICU가 전체 유니 코드 데이터 정렬 알고리즘strcoll사용하고 ISO 14651 을 사용 한다는 것 입니다.

이 두 알고리즘의 차이점은 http://unicode.org/faq/collation.html#13에 간략하게 요약되어 있습니다 . 이것은 실제로는 거의 중요하지 않은 다소 이국적인 특수한 경우입니다.

>>> import icu # pip install PyICU
>>> sorted(['a','b','c','ä'])
['a', 'b', 'c', 'ä']
>>> collator = icu.Collator.createInstance(icu.Locale('de_DE.UTF-8'))
>>> sorted(['a','b','c','ä'], key=collator.getSortKey)
['a', 'ä', 'b', 'c']

Python 2와 Python 3에서 동일하게 작동합니까? 나는 locale.strxfrmu0b34a0f6ae의 답변에서 사용 했으며 작동하는 것처럼 보이고 훨씬 우아하며 추가 소프트웨어가 필요하지 않습니다.
sup

나를 위해 Python3에서 작동하지 않고 sudo pip3 install PyICU설치에 실패하며 Python2에서도 마찬가지입니다.
imrek

Pip에서 컴파일하고 설치하려면 pyICU 용 libicu-devel.x86_64를 설치해야했습니다. 작동하지만 마지막 'sorted'명령의 출력은 다음과 같습니다. [ 'a', '\ xc3 \ xa4', 'b', 'c']
Mike Stoddart

53

나는 대답에서 이것을 보지 못합니다. 내 응용 프로그램은 Python의 표준 라이브러리를 사용하여 로케일에 따라 정렬됩니다. 꽤 쉽습니다.

# python2.5 code below
# corpus is our unicode() strings collection as a list
corpus = [u"Art", u"Älg", u"Ved", u"Wasa"]

import locale
# this reads the environment and inits the right locale
locale.setlocale(locale.LC_ALL, "")
# alternatively, (but it's bad to hardcode)
# locale.setlocale(locale.LC_ALL, "sv_SE.UTF-8")

corpus.sort(cmp=locale.strcoll)

# in python2.x, locale.strxfrm is broken and does not work for unicode strings
# in python3.x however:
# corpus.sort(key=locale.strxfrm)

Lennart 및 기타 답변자에게 질문 : '로케일'을 아는 ​​사람이 없습니까? 아니면이 작업에 맞지 않습니까?


그건 그렇고 1) 나는 locale.strxfrm이 UTF-8 인코딩`str '에 대해 깨 졌다고 생각하지 않습니다. 응용 프로그램에서 벤치마킹 한 결과 유니 코드 객체에서 cmp = strcoll을 사용하는 것이 UTF-8로 모두 디코딩하고 key = strxfrm을 사용하는 것보다 저렴하다는 결론을 내 렸습니다
u0b34a0f6ae

6
그런데 2) 로케일 모듈은 임의의 로케일이 아닌 생성 된 로케일 (Linux 상자의 경우)에서만 작동합니다. "locale -a"는
u0b34a0f6ae를

6
@Georg : 로케일은 단순한 하위 문자열-> collating_element 매핑 만 지원한다고 생각합니다. 확장 (æ "ae"로 정렬 됨), 프랑스어 악센트 정렬 (문자는 왼쪽에서 오른쪽으로 정렬되지만 악센트는 오른쪽에서 왼쪽으로 정렬 됨), 재 배열 등을 처리하지 않습니다. 세부 정보 (전체 UCA 기능 세트) : unicode.org/reports/tr10 및 여기 (로케일 데이터 정렬) : chm.tu-dresden.de/edv/manuals/aix/files/aixfiles/LC_COLLATE.htm
Rafał Dowgird

2
명확하게 질문에 대답하기 : 네, 그것은 입니다 작업까지. 완전한 유니 코드 데이터 정렬 알고리즘이 더 잘 처리하는 몇 가지 특별한 경우가 분명히 있지만, 기회가 있다는 것을 이미 알고 있지 않으면 눈치 채지 못할 것입니다.
Lennart Regebro

1
여기서 가장 큰 문제는 전체 응용 프로그램에 대해 전역 적으로 로케일을 설정해야한다는 것입니다. – 비교를 위해 가지고있을 수는 없습니다.
Robert Siemer 2015-04-05

9

James Tauber의 Python Unicode Collation Algorithm을 사용해보십시오 . 원하는대로 정확하게 수행되지 않을 수 있지만 살펴볼 가치가있는 것 같습니다. 문제에 대한 자세한 정보는 Christopher Lenz 의이 게시물 을 참조하십시오 .


적어도 일반적인 문제를 해결합니다. 언어에 민감한 버전의 데이터 정렬 목록도 만들 수 있다고 생각합니다.
Lennart Regebro 2007

로케일을 지정할 수 없으며 참조 구성 파일로 인해 ValueError가 발생합니다.
thebjorn

8

pyuca에 관심이있을 수도 있습니다 .

http://jtauber.com/blog/2006/01/27/python_unicode_collation_algorithm/

확실히 가장 정확한 방법은 아니지만 최소한 어느 정도 옳게 만드는 아주 간단한 방법입니다. 또한 로케일이 스레드 세이프가 아니고 프로세스 전반에 걸쳐 언어 설정을 설정하기 때문에 웹앱에서 로케일을 능가합니다. 또한 외부 C 라이브러리에 의존하는 PyICU보다 설정하기 쉽습니다.

이 글을 쓰는 시점에 원본이 다운 되었기 때문에 스크립트를 github에 업로드했으며이를 얻기 위해 웹 캐시에 의존해야했습니다.

https://github.com/href/Python-Unicode-Collation-Algorithm

이 스크립트를 사용하여 plone 모듈에서 독일어 / 프랑스어 / 이탈리아어 텍스트를 올바르게 정렬했습니다.


퓨카 +1. 상당히 빠르며 (28000 개의 단어를 정렬하는 데 3 초) 순수한 파이썬이며 종속성이 필요하지 않습니다.
michaelmeyer 2013 년

7

요약 및 확장 답변 :

locale.strcollPython 2 locale.strxfrm에서 실제로 문제를 해결하고 문제의 로케일이 설치되어 있다고 가정하면 실제로 문제를 해결할 수 있습니다. 로케일 이름이 혼란스럽게 다른 Windows에서도 테스트했지만 다른 한편으로는 기본적으로 지원되는 모든 로케일이 설치되어있는 것 같습니다.

ICU실제로이 작업을 더 잘 수행하는 것은 아니지만 훨씬 더 많은 작업을 수행 합니다. 특히 다른 언어로 된 텍스트를 단어로 분할 할 수있는 스플리터를 지원합니다. 이것은 단어 구분 기호가없는 언어에 매우 유용합니다. 하지만 포함되어 있지 않기 때문에 분할의 기본으로 사용할 단어 모음이 있어야합니다.

또한 로케일에 대한 긴 이름을 가지고 있으므로 로케일에 대한 예쁜 표시 이름, Gregorian 이외의 다른 달력에 대한 지원 (Python 인터페이스가 지원하는지 확실하지 않음) 및 기타 다소 모호한 로케일 지원의 톤과 톤을 얻을 수 있습니다. .

따라서 전체적으로 : 알파벳순으로 로케일에 따라 정렬하려는 경우 locale특별한 요구 사항이 없거나 단어 분할기와 같은 더 많은 로케일 종속 기능이 필요한 경우가 아니면 모듈을 사용할 수 있습니다 .


6

나는 대답이 이미 훌륭한 작업을 수행했음을 알았습니다 . Human Sort의 코딩 비 효율성을 지적하고 싶었습니다 . 선택적 문자 별 변환을 유니 코드 문자열 s에 적용하려면 다음 코드를 사용합니다.

spec_dict = {'Å':'A', 'Ä':'A'}

def spec_order(s):
    return ''.join([spec_dict.get(ch, ch) for ch in s])

파이썬은이 보조 작업을 수행하는 훨씬 더 좋고 빠르며 간결한 방법을 가지고 있습니다 (유니 코드 문자열에서-바이트 문자열에 대한 유사한 방법은 다소 덜 도움이되는 사양을 가지고 있습니다!-) :

spec_dict = dict((ord(k), spec_dict[k]) for k in spec_dict)

def spec_order(s):
    return s.translate(spec_dict)

translate메서드에 전달하는 dict 에는 유니 코드 서수 (문자열 아님)가 키로 있으므로 원래 char-to-char에서 다시 빌드하는 단계가 필요합니다 spec_dict. ([서수 여야하는 키와는 반대로] 번역하기 위해 전달하는 dict의 값은 유니 코드 서수, 임의의 유니 코드 문자열 또는 번역의 일부로 해당 문자를 제거하기위한 None 일 수 있으므로 "ignore a 정렬 목적을위한 특정 문자 ","정렬 목적을 위해 ä를 ae에 매핑 "등).

Python 3에서는 "재 구축"단계를 더 간단하게 수행 할 수 있습니다. 예 :

spec_dict = ''.maketrans(spec_dict)

Python 3 에서이 정적 메서드를 사용할 수있는 다른 방법 은 문서 를 참조하세요 maketrans.


이 방법은 좋지만 az와 b 사이에 á를 넣을 수는 없습니다
Barney


1

최근 에이 작업에 zope.ucol ( https://pypi.python.org/pypi/zope.ucol )을 사용하고 있습니다. 예를 들어, 독일어 ß 정렬 :

>>> import zope.ucol
>>> collator = zope.ucol.Collator("de-de")
>>> mylist = [u"a", u'x', u'\u00DF']
>>> print mylist
[u'a', u'x', u'\xdf']
>>> print sorted(mylist, key=collator.key)
[u'a', u'\xdf', u'x']

zope.ucol도 ICU를 래핑하므로 PyICU의 대안이 될 것입니다.


1

완벽한 UCA 솔루션

표준 Unicode :: Collate 모듈 의 하위 클래스 인 Perl 라이브러리 모듈 Unicode :: Collate :: Locale에 대한 콜 아웃을 만드는 가장 간단하고 가장 쉽고 가장 간단한 방법 입니다. 스웨덴 에 대한 로케일 값을 생성자에 전달 하기 만하면됩니다. "xv"

(스웨덴어 텍스트에 대해서는이 기능을 꼭 사용하지 않을 수 있지만 Perl은 추상 문자를 사용하기 때문에 플랫폼이나 빌드에 관계없이 원하는 모든 유니 코드 코드 포인트를 사용할 수 있습니다. 이러한 편의를 제공하는 언어는 거의 없습니다. 최근이 미친 문제로 인해 Java와의 싸움에서 많이지고 있습니다.)

문제는 Python에서 Perl 모듈에 액세스하는 방법을 모른다는 것입니다. 즉, 쉘 콜 아웃이나 양면 파이프를 사용하는 것과는 다릅니다. 이를 위해 ucsort 라는 완전한 작업 스크립트를 제공하여 요청한 것을 완벽하게 쉽게 수행 할 수 있습니다.

이 스크립트는 전체 유니 코드 데이터 정렬 알고리즘 과 100 % 호환 되며 모든 맞춤 옵션이 지원됩니다 !! 옵션 모듈이 설치되어 있거나 Perl 5.13 이상을 실행하는 경우 사용하기 쉬운 CLDR 로케일에 대한 전체 액세스 권한이 있습니다. 아래를 참조하십시오.

데모

다음과 같이 정렬 된 입력 세트를 상상해보십시오.

b o i j n l m å y e v s k h d f g t ö r x p z a ä c u q

코드 포인트 별 기본 정렬은 다음과 같습니다.

a b c d e f g h i j k l m n o p q r s t u v x y z ä å ö

모든 사람의 책에서 잘못되었습니다. Unicode Collation Algorithm을 사용하는 스크립트를 사용하면 다음과 같은 순서를 얻을 수 있습니다.

% perl ucsort /tmp/swedish_alphabet | fmt
a å ä b c d e f g h i j k l m n o ö p q r s t u v x y z

이것이 기본 UCA 정렬입니다. 스웨덴어 로케일을 얻으려면 다음과 같이 ucsort를 호출 하십시오 .

% perl ucsort --locale=sv /tmp/swedish_alphabet | fmt
a b c d e f g h i j k l m n o p q r s t u v x y z å ä ö

다음은 더 나은 입력 데모입니다. 먼저 입력 세트 :

% fmt /tmp/swedish_set
cTD cDD Cöd Cbd cAD cCD cYD Cud cZD Cod cBD Cnd cQD cFD Ced Cfd cOD
cLD cXD Cid Cpd cID Cgd cVD cMD cÅD cGD Cqd Cäd cJD Cdd Ckd cÖD cÄD
Ctd Czd Cxd cHD cND cKD Cvd Chd Cyd cUD Cld Cmd cED Crd Cad Cåd Ccd
cRD cSD Csd Cjd cPD

코드 포인트별로 다음과 같이 정렬됩니다.

Cad Cbd Ccd Cdd Ced Cfd Cgd Chd Cid Cjd Ckd Cld Cmd Cnd Cod Cpd Cqd
Crd Csd Ctd Cud Cvd Cxd Cyd Czd Cäd Cåd Cöd cAD cBD cCD cDD cED cFD
cGD cHD cID cJD cKD cLD cMD cND cOD cPD cQD cRD cSD cTD cUD cVD cXD
cYD cZD cÄD cÅD cÖD

그러나 기본 UCA를 사용하면 다음과 같이 정렬됩니다.

% ucsort /tmp/swedish_set | fmt
cAD Cad cÅD Cåd cÄD Cäd cBD Cbd cCD Ccd cDD Cdd cED Ced cFD Cfd cGD
Cgd cHD Chd cID Cid cJD Cjd cKD Ckd cLD Cld cMD Cmd cND Cnd cOD Cod
cÖD Cöd cPD Cpd cQD Cqd cRD Crd cSD Csd cTD Ctd cUD Cud cVD Cvd cXD
Cxd cYD Cyd cZD Czd

그러나 스웨덴어 로케일에서는 다음과 같이됩니다.

% ucsort --locale=sv /tmp/swedish_set | fmt
cAD Cad cBD Cbd cCD Ccd cDD Cdd cED Ced cFD Cfd cGD Cgd cHD Chd cID
Cid cJD Cjd cKD Ckd cLD Cld cMD Cmd cND Cnd cOD Cod cPD Cpd cQD Cqd
cRD Crd cSD Csd cTD Ctd cUD Cud cVD Cvd cXD Cxd cYD Cyd cZD Czd cÅD
Cåd cÄD Cäd cÖD Cöd

대문자를 소문자보다 먼저 정렬하려면 다음과 같이하십시오.

% ucsort --upper-before-lower --locale=sv /tmp/swedish_set | fmt
Cad cAD Cbd cBD Ccd cCD Cdd cDD Ced cED Cfd cFD Cgd cGD Chd cHD Cid
cID Cjd cJD Ckd cKD Cld cLD Cmd cMD Cnd cND Cod cOD Cpd cPD Cqd cQD
Crd cRD Csd cSD Ctd cTD Cud cUD Cvd cVD Cxd cXD Cyd cYD Czd cZD Cåd
cÅD Cäd cÄD Cöd cÖD

맞춤 정렬

ucsort로 다른 많은 일을 할 수 있습니다 . 예를 들어 다음은 영어로 제목을 정렬하는 방법입니다.

% ucsort --preprocess='s/^(an?|the)\s+//i' /tmp/titles
Anathem
The Book of Skulls
A Civil Campaign
The Claw of the Conciliator
The Demolished Man
Dune
An Early Dawn
The Faded Sun: Kesrith
The Fall of Hyperion
A Feast for Crows
Flowers for Algernon
The Forbidden Tower
Foundation and Empire
Foundations Edge
The Goblin Reservation
The High Crusade
Jack of Shadows
The Man in the High Castle
The Ringworld Engineers
The Robots of Dawn
A Storm of Swords
Stranger in a Strange Land
There Will Be Time
The White Dragon

일반적으로 스크립트를 실행하려면 Perl 5.10.1 이상이 필요합니다. 로케일 지원을 위해서는 선택적 CPAN 모듈을 설치해야합니다 Unicode::Collate::Locale. 또는 해당 모듈을 표준으로 포함하는 Perl, 5.13+의 개발 버전을 설치할 수 있습니다.

호출 규칙

이것은 빠른 프로토 타입이므로 ucsort 는 대부분 문서화되지 않았습니다 . 그러나 이것은 명령 줄에서 수락하는 스위치 / 옵션의 개요입니다.

    # standard options
    --help|?
    --man|m
    --debug|d

    # collator constructor options
    --backwards-levels=i
    --collation-level|level|l=i
    --katakana-before-hiragana
    --normalization|n=s
    --override-CJK=s
    --override-Hangul=s
    --preprocess|P=s
    --upper-before-lower|u
    --variable=s

    # program specific options
    --case-insensitive|insensitive|i
    --input-encoding|e=s
    --locale|L=s
    --paragraph|p
    --reverse-fields|last
    --reverse-output|r
    --right-to-left|reverse-input

예, Getopt::Long좋습니다. 이것이 제가를 호출하는 데 사용하는 인수 목록 입니다.하지만 아이디어를 얻을 수 있습니다. :)

Perl 스크립트를 호출하지 않고 Python에서 직접 Perl 라이브러리 모듈을 호출하는 방법을 알아낼 수 있다면 반드시 그렇게하십시오. 나는 나 자신을 모른다. 방법을 배우고 싶습니다.

그 동안 저는이 스크립트가 모든 특정 작업에서 필요한 작업을 수행 할 것이라고 믿습니다 . 이제 모든 텍스트 정렬에 이것을 사용합니다. 그것은 결국 내가 오래, 오래 시간을 필요로 한 것을 않습니다.

유일한 단점은 --locale논증으로 인해 성능이 튜브 아래로 떨어질 수 있다는 것입니다.하지만 정규적이고 비 로케일 에는 충분히 빠르지 만 여전히 100 % UCA 준수 정렬입니다. 모든 것을 메모리에로드하기 때문에 기가 바이트 문서에 사용하고 싶지 않을 것입니다. 나는 하루에 여러 번 그것을 사용하고 마침내 정상적인 텍스트 정렬을 갖는 것이 좋습니다.


2
도대체 왜 Python 라이브러리가있는 작업을 수행하기 위해 Perl 스크립트를 호출할까요?
Lennart Regebro

2
파이썬 라이브러리 있다는 것을 몰랐기 때문에 그 이유입니다!
tchrist

@Lennart : 저는 네이티브 라이브러리를 선호합니다. 또는 C API에 연결되고 동적으로로드되는 라이브러리 (때로는 필요함)를 최대한 선호합니다. 나는 다양한 PyPerl 및 Inline :: Perl 솔루션이 매우 설득력 있고 견고하거나 유연하다는 것을 찾지 못했습니다. 또는 뭔가. 그들은 몇 가지 이유로 옳지 않다고 생각합니다. 나는 좋은 문자 집합 감지가 필요할 때 마지막으로 시도했습니다 (아아도 얻지 못했습니다).
tchrist

4
Python 내부에서 Perl을 사용하는 것은 중독 일뿐입니다.
Utku Zihnioglu

1
와. 네-저에게는 Perl처럼 보입니다. 사실 우리는 이제 일을하는 두 가지 이상의 방법이 있다는 것을 알았습니다. :) 그러나 Python에서 C를 호출하는 것은 일반적으로 Perl을 호출하는 것과 같은 추가 된 종속성과 실질적인 지원 문제를 의미하지 않습니다. 이런 식으로해야하는 많은 요구를보기가 몹시 어렵습니다.
nealmcb

0

그것은 당신의 사용 사례를위한 완벽한 솔루션에서 멀리이다, 그러나 당신은 한 번 봐 걸릴 수 unaccent.py effbot.org에서 스크립트를. 기본적으로하는 일은 텍스트에서 모든 악센트를 제거하는 것입니다. '정리 된'텍스트를 사용하여 알파벳순으로 정렬 할 수 있습니다. (더 자세한 설명은 페이지를 참조 하십시오.)


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.