2009-02-05 3 views
299

파이썬에서 유니 코드 문자열을 가지고 있으며 모든 악센트 (발음 구별 기호)를 제거하고 싶습니다.파이썬 유니 코드 문자열에서 악센트를 제거하는 가장 좋은 방법은 무엇입니까?

  1. 모든 문자를 제거 (문자와 발음 구별 부호에 대한 별도의 문자) 긴 표준화 형식으로 유니 코드 문자열을 변환 :

    나는 웹에서 자바에서이 작업을 수행하는 우아한 방법을 발견 그의 유니 코드 유형은 "분음 부호"입니다.

pyICU와 같은 라이브러리를 설치해야합니까, 아니면 파이썬 표준 라이브러리만으로 가능합니까? 파이썬 3은 어떨까요?

중요 사항 : 악센트 부호가있는 문자를 액센트가없는 문자로 명시 적으로 매핑하는 코드는 피하고 싶습니다.

답변

230

Unidecode이 정답입니다. 유니 코드 문자열을 ASCII 텍스트에서 가능한 가장 가까운 표현으로 변환합니다.

예 :

accented_string = u'Málaga' 
# accented_string is of type 'unicode' 
import unidecode 
unaccented_string = unidecode.unidecode(accented_string) 
# unaccented_string contains 'Malaga'and is of type 'str' 
+0

그래,이 방법은 단순히 액센트를 제거하는 것보다 나은 해결책입니다. ASCII로 단어를 작성하기위한 규칙이있는 언어에 대해 훨씬 더 유용한 음역을 제공합니다. –

+34

중국어와 잘 어울리는 것 같지만 불행하게도 "François"라는 프랑스어 이름의 변형은 더 자연스럽지 않은 "Francois"에 비해 "Franassois"를 제공하지 못합니다. – EOL

+8

은 달성하려는 목표에 따라 다릅니다. 예를 들어 지금은 수색 중입니다. 그리스어/러시아어/중국어를 음역하고 싶지 않으므로 "±/ę/ś/ć"를 "a/e/s/c"로 바꾸고 싶습니다. – kolinko

112

난 그냥 웹에서이 대답을 발견

import unicodedata 

def remove_accents(input_str): 
    nfkd_form = unicodedata.normalize('NFKD', input_str) 
    only_ascii = nfkd_form.encode('ASCII', 'ignore') 
    return only_ascii 

그것은 (예를 들어, 프랑스어) 잘 작동하지만 내가 두 번째 단계는 (악센트를 제거) 비를 떨어보다 더 처리 할 수 ​​있다고 생각 일부 언어 (예 : 그리스어)에서는 실패 할 것이기 때문에 -ASCII 문자를 사용하십시오. 가장 좋은 해결책은 분음 부호로 태그 지정된 유니 코드 문자를 명시 적으로 제거하는 것입니다.

편집 : 문자 c가 선행 문자와 결합 할 수있는 경우

import unicodedata 

def remove_accents(input_str): 
    nfkd_form = unicodedata.normalize('NFKD', input_str) 
    return u"".join([c for c in nfkd_form if not unicodedata.combining(c)]) 

unicodedata.combining(c)

그것이 분음 부호 인 경우 즉, 주로, true를 돌려줍니다 :이 트릭을 수행합니다.

편집 2는 : remove_accents유니 코드 문자열이 아닌 바이트 문자열을 기대하고있다. 당신이 바이트 문자열이있는 경우, 당신은이 같은 유니 코드 문자열로 디코딩해야합니다

encoding = "utf-8" # or iso-8859-15, or cp1252, or whatever encoding you use 
byte_string = b"café" # or simply "café" before python 3. 
unicode_string = byte_string.decode(encoding) 
+5

유니 코드에 'utf8'을 추가해야했습니다 :'nkfd_form = unicodedata.normalize ('NFKD', 유니 코드 (input_str, 'utf8'))' – Jabba

+0

@Jabba :', 'utf8''은 "안전망" 터미널에서 입력을 테스트하는 경우 필요합니다 (기본적으로 유니 코드를 사용하지 않습니다). 하지만 대개는 액센트를 없애면 input_str이 utf8이 될 가능성이 높으므로 추가 할 필요가 없습니다. 안전하다고 상처주지 않습니다. – MestreLion

+0

>>> def remove_accents (input_str) : ... nkfd_form = unicodedata.normalize ('NFKD', unicode (input_str)) ... return ""조인 (unicodedata가 아닌 경우 nkfd_form의 c를 반환합니다. 결합 (C)]) 마지막 ... >>> remove_accents ('E') 역 추적 (가장 최근 통화) : 파일 ""라인 1 "" 파일에서, 2 호선에서 remove_accents UnicodeDecodeError : 'ascii'코덱은 위치 0에서 바이트 0xc3을 디코딩 할 수 없습니다. 서수가 범위 내에 없습니다 (128) – rbp

211

이 방법에 대해 :

이 너무, 그리스 문자에서 작동
import unicodedata 
def strip_accents(s): 
    return ''.join(c for c in unicodedata.normalize('NFD', s) 
        if unicodedata.category(c) != 'Mn') 

:

>>> strip_accents(u"A \u00c0 \u0394 \u038E") 
u'A A \u0394 \u03a5' 
>>> 

character category "Mn"은 Nonspacing_Mark을 나타내며, 이는 MiniQuark의 대답에서 unicodedata.combining과 유사합니다 (나는 unicodedata.combining을 생각하지 않았지만 아마 더 나은 soluti입니다 더 명확하기 때문에).

이러한 조작은 텍스트의 의미를 크게 변경시킬 수 있습니다. 악센트, 움 오토 등은 "장식"이 아닙니다.

+5

불행히도 "³"은 "라틴 소문자 L 스트로크"라는 이름이 붙어 있어도 이러한 문자는 작곡되지 않습니다! 여러분은'unicodedata.name'을 파싱하여 게임을하거나, 어쨌든 그리스 문자에 필요한 유사 표를 분해하여 사용해야합니다 (Α는 단지 "그리스 자본 문자 알파"임). – alexis

+0

@alexis https://mail.python.org/pipermail/python-list/2007-October/446440.html – andi

+0

@andi, 나는 당신이 원하는 지점을 짐작할 수 없습니다. 전자 메일 교환은 위의 내용을 반영합니다. 문자 "ł"는 악센트 부호가없는 문자이므로 유니 코드 표준으로 처리되지 않으므로 분해되지 않습니다. – alexis

11

이 (에서 ø 등)뿐만 아니라 악센트, 또한 "스트로크"를 처리합니다

import unicodedata as ud 

def rmdiacritics(char): 
    ''' 
    Return the base character of char, by "removing" any 
    diacritics like accents or curls and strokes and the like. 
    ''' 
    desc = ud.name(unicode(char)) 
    cutoff = desc.find(' WITH ') 
    if cutoff != -1: 
     desc = desc[:cutoff] 
    return ud.lookup(desc) 

이것은 내가 생각할 수있는 가장 우아한 방법 (이다 그리고 그것은이 페이지에 대한 코멘트에서 alexis에 의해 언급되었습니다.) 비록 그것이 실제로 매우 우아하다고는 생각하지 않지만.

유니 코드 이름에 'WITH'가 없기 때문에 뒤집힌 문자와 같이 특수 문자가 여전히 처리됩니다. 그것은 당신이 어쨌든하고 싶은 것에 달려 있습니다. 때로 사전 정렬 순서를 달성하기 위해 악센트 스트립 핑이 필요했습니다. @ MiniQuark의 대답에 대응

+4

새 기호가없는 경우 예외를 catch해야합니다. 예를 들어 VERTICAL FILL S이있는 SQUARE가 있지만 SQUARE는 없습니다. (이 코드가 UMBRELLA를 RAIN DROPS WITH로 변환하여 UMBRELLA ☔로 변환한다는 것은 말할 필요도 없음). – janek37

10

:

나는 반 프랑스어 (포함 악센트)이었다 csv 파일에서 읽으려고하고 일부 문자열은 결국 정수와 수레가 될 것이다.

Montréal, über, 12.89, Mère, Françoise, noël, 889

나는 그것이 (내가 파이썬 티켓에 발견하는) 일을 얻을뿐만 아니라, 통합 라인 23을 포함했다 @ 시험으로,이 닮은 test.txt 파일을 생성 자바 더의 코멘트 :

import sys 
reload(sys) 
sys.setdefaultencoding("utf-8") 
import csv 
import unicodedata 

def remove_accents(input_str): 
    nkfd_form = unicodedata.normalize('NFKD', unicode(input_str)) 
    return u"".join([c for c in nkfd_form if not unicodedata.combining(c)]) 

with open('test.txt') as f: 
    read = csv.reader(f) 
    for row in read: 
     for element in row: 
      print remove_accents(element) 

결과 :

Montreal 
uber 
12.89 
Mere 
Francoise 
noel 
889 

(참고 : 나는 맥 OS X 10.8.4에 오전 2.7.3 파이썬 사용)

+1

'remove_accents'는 유니 코드 문자열에서 악센트를 제거하기위한 것이 었습니다. 그것은 바이트 문자열을 통과 할 경우,'unicode (input_str)'을 사용하여 유니 코드 문자열로 변환하려고합니다. 파이썬의 기본 인코딩 인 "ascii"를 사용합니다. 파일이 UTF-8로 인코딩되었으므로 실패합니다. 라인 2와 3은 파이썬의 기본 인코딩을 UTF-8로 바꾼다. 그래서 당신이 알아 낸 것처럼 작동한다. 또 다른 옵션은 unicode 문자열'remove_accents'를 전달하는 것입니다 : 행 2와 행 3을 제거하고, 마지막 줄에서'element.d'를'element.decode ("utf-8")'로 대체하십시오. 나는 시험했다 : 그것은 작동한다. 이 답변을 명확하게하기 위해 답변을 업데이트하겠습니다. – MiniQuark

+0

좋은 편집, 좋은 지적. (다른 메모 : 내가 깨닫은 진짜 문제는 나의 데이터 파일이'iso-8859-1'에 인코딩되어 있다는 것입니다. 불행하게도이 함수로 작업 할 수 없습니다!) – aseagram

+0

aseagram : 단순히 " utf-8 "을"iso-8859-1 "로 바꾸십시오. 창문에 있다면 "cp1252"를 대신 사용해야합니다. – MiniQuark

14

사실 나는 프로젝트 호환 Python 2.6, 2.7 및 3.4에서 작업하며 자유 사용자 항목에서 ID를 만들어야합니다.

당신 덕택에이 기능을 만들었습니다.

import re 
import unicodedata 

def strip_accents(text): 
    """ 
    Strip accents from input String. 

    :param text: The input string. 
    :type text: String. 

    :returns: The processed String. 
    :rtype: String. 
    """ 
    try: 
     text = unicode(text, 'utf-8') 
    except (TypeError, NameError): # unicode is a default on python 3 
     pass 
    text = unicodedata.normalize('NFD', text) 
    text = text.encode('ascii', 'ignore') 
    text = text.decode("utf-8") 
    return str(text) 

def text_to_id(text): 
    """ 
    Convert input text to id. 

    :param text: The input string. 
    :type text: String. 

    :returns: The processed String. 
    :rtype: String. 
    """ 
    text = strip_accents(text.lower()) 
    text = re.sub('[ ]+', '_', text) 
    text = re.sub('[^0-9a-zA-Z_-]', '', text) 
    return text 

결과 :

text_to_id("Montréal, über, 12.89, Mère, Françoise, noël, 889") 
>>> 'montreal_uber_1289_mere_francoise_noel_889' 
+0

python3의 유니 코드 문자열 : http://stackoverflow.com/a/6812069/1569144 – Jer42

+2

Py2.7에서는 이미 유니 코드 문자열을 'text = unicode (text,'utf-8 ')'에 전달합니다. 이에 대한 해결 방법은'Except TypeError를 추가하는 것입니다 : pass' –

+0

무엇이 있는지 모르지만 작동합니다 (Y) –

0

일부 언어가 악센트를 지정하는 언어 문자와 악센트 발음 구별 부호와 같은 발음 구별 부호를 조합했다.

나는 당신이 제거 할 diactrics 것을 명시 적으로 지정하는 것이 더 안전하다고 생각 :

def strip_accents(string, accents=('COMBINING ACUTE ACCENT', 'COMBINING GRAVE ACCENT', 'COMBINING TILDE')): 
    accents = set(map(unicodedata.lookup, accents)) 
    chars = [c for c in unicodedata.normalize('NFD', string) if c not in accents] 
    return unicodedata.normalize('NFC', ''.join(chars)) 
6
import unicodedata 
s = 'Émission' 
search_string = ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')) 

파이썬 2.X를 들어 파이썬 3.X

print (search_string) 

를 들어

print search_string 
+2

이것은 잘 작동하는 것 같습니다. 'unidecode'는'deg'를'deg'로 변환합니다. 이것은 원하는 동작이 아닐 수도 있습니다. –

0

gensim.utils.deaccent(text)Gensim - topic modelling for humans에서 :

deaccent("Šéf chomutovských komunistů dostal poštou bílý prášek") 'Sef chomutovskych komunistu dostal postou bily prasek'

또 다른 해결책은 unidecode입니다.

하지 전형적 일부 문자에 억양을 제거 한편 UnicodeData와 제안 된 해결책은 (예를 들어, 오히려 'l'에보다 '''ł' 변) 있음.

관련 문제