web-dev-qa-db-ja.com

PythonのUnicode文字列からアクセントを削除するための最良の方法は何ですか?

私はPythonのUnicode文字列を持っています、そして私はすべてのアクセント(発音区別符号)を取り除きたいです。

私はWeb上でこれをJavaで実行するためのエレガントな方法を見つけました。

  1. unicode文字列を長い正規化形式に変換します(文字と発音区別符号には別の文字を使用)。
  2. unicodeタイプが「発音区別符号」であるすべての文字を削除します。

PyICUなどのライブラリをインストールする必要がありますか、それともpython標準ライブラリだけで可能ですか?そして、Python 3はどうですか?

重要な注意:アクセント記号付きの文字からアクセント記号なしの対応する部分への明示的なマッピングを伴うコードは避けたいと思います。

425
MiniQuark

Unidecode が正しい答えです。 Unicode文字列を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'
352

これはどう:

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'
>>> 

文字カテゴリ "Mn"はNonspacing_Markを表します。これは、MiniQuarkの回答のunicodedata.combiningに似ています(unicodedata.combiningは考えていませんでしたが、それはより明確なので、おそらくそれはより良い解決策です。

そして、覚えておいてください、これらの操作はテキストの意味を著しく変えるかもしれません。アクセント、ウムラウトなどは「装飾」ではありません。

250
oefe

私はちょうどWeb上でこの答えを見つけました:

import unicodedata

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

これはうまく機能します(たとえばフランス語の場合)が、2番目のステップ(アクセントの削除)は非ASCII文字を削除するよりもうまく処理できると思います。最善の解決策は、発音区別符号としてタグ付けされているUnicode文字を明示的に削除することです。

編集:これはトリックです:

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)])

文字cが直前の文字と結合できる場合、つまり主に発音区別符号である場合、unicodedata.combining(c)はtrueを返します。

編集2remove_accentsはバイト文字列ではなくユニコード文字列を期待します。バイト文字列がある場合は、それを次のようなUnicode文字列にデコードする必要があります。

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)
129
MiniQuark

実際、私はプロジェクト互換の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'
28
jer1can

これはアクセントだけでなく "ストローク"も扱います(øなど)。

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'が含まれていないため、これまでに処理されていない特殊な文字(回転文字や反転文字など)がまだあります。とにかくやりたいことによります。辞書のソート順を達成するためにアクセントの削除が必要になることがありました。

16
lenz

@ MiniQuarkの回答に答えて:

私は(アクセントを含む)半フランス語のcsvファイルを読み込もうとしていましたが、最終的に整数や浮動小数点数になることもありました。テストとして、私は次のような外観のtest.txtファイルを作成しました。

モントリオール、über、12.89、その他、Françoise、noël、889

私はそれを動かすために23の行を含めなければなりません(私はpythonチケットで見つけました)、そして@ Jabbaのコメントを取り入れます:

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

(注:私はMac OS X 10.8.4を使用していて、Python 2.7.3を使用しています)

11
aseagram

gensim.utils.deaccent(text) から Gensim - トピックモデリングのための人間

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

別の解決策は unidecode です。

unicodedataを使用して提案された解決策は、通常、ある文字のみでアクセントを削除します(たとえば、'ł'ではなく'''l'に変換します)。

10
Piotr Migdal

一部の言語では、アクセント記号を指定するために、言語文字としての発音区別符号とアクセント記号の発音区別符号の組み合わせがあります。

どの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))
1
sirex