5

大きなドキュメントから、アクセント付きのE、左右の引用符などのすべての高いUnicode文字を、通常の「E」やまっすぐな引用符などの低範囲の「通常の」対応文字に置き換えたいと考えています。非常に大きなドキュメントでこれを頻繁に実行する必要があります。私はここでperlかもしれないと思うものでこれの例を見ます:http ://www.designmeme.com/mtplugins/lowdown.txt

s.replace(...)。replace(...)。replace(...)...を使用せずにPythonでこれを行う高速な方法はありますか?数文字を置き換えてみましたが、ドキュメントのストリッピングが非常に遅くなりました。

編集、動作していないように見えるunutbuのコードの私のバージョン:

# -*- coding: iso-8859-15 -*-
import unidecode
def ascii_map():
    data={}
    for num in range(256):
        h=num
        filename='x{num:02x}'.format(num=num)
        try:
            mod = __import__('unidecode.'+filename,
                             fromlist=True)
        except ImportError:
            pass
        else:
            for l,val in enumerate(mod.data):
                i=h<<8
                i+=l
                if i >= 0x80:
                    data[i]=unicode(val)
    return data

if __name__=='__main__':
    s = u'“fancy“fancy2'
    print(s.translate(ascii_map()))
4

5 に答える 5

8
# -*- encoding: utf-8 -*-
import unicodedata

def shoehorn_unicode_into_ascii(s):
    return unicodedata.normalize('NFKD', s).encode('ascii','ignore')

if __name__=='__main__':
    s = u"éèêàùçÇ"
    print(shoehorn_unicode_into_ascii(s))
    # eeeaucC

@Mark Tolonenが親切に指摘しているように、上記の方法では、ß''“”などの一部の文字が削除されることに注意してください。上記のコードが翻訳したい文字を切り捨てる場合は、文字列のtranslateメソッドを使用してこれらの問題を手動で修正する必要がある場合があります。もう1つのオプションは、unidecodeを使用することです(JF Sebastianの回答を参照)。

大きなUnicode文字列がある場合、そのtranslateメソッドを使用すると、メソッドを使用するよりもはるかに高速になりますreplace

編集: unidecodeユニコードコードポイントのASCIIへのより完全なマッピングがあります。ただし、unidecode.unidecode文字列を文字ごとにループします(Pythonループ内)。これは、translateメソッドを使用するよりも低速です。

次のヘルパー関数はunidecode、のデータファイルとtranslate、特に長い文字列の場合に速度を向上させるためのメソッドを使用します。

1〜6 MBのテキストファイルでの私のテストでは、使用ascii_mapは。よりも約4〜6倍高速ですunidecode.unidecode

# -*- coding: utf-8 -*-
import unidecode
def ascii_map():
    data={}
    for num in range(256):
        h=num
        filename='x{num:02x}'.format(num=num)
        try:
            mod = __import__('unidecode.'+filename,
                             fromlist=True)
        except ImportError:
            pass
        else:
            for l,val in enumerate(mod.data):
                i=h<<8
                i+=l
                if i >= 0x80:
                    data[i]=unicode(val)
    return data

if __name__=='__main__':
    s = u"éèêàùçÇ"
    print(s.translate(ascii_map()))
    # eeeaucC

Edit2:Rhubarb、SyntaxError# -*- encoding: utf-8 -*-が発生している場合は、試してください # -*- encoding: cp1252 -*-。宣言するエンコーディングは、テキストエディタがファイルの保存に使用するエンコーディングによって異なります。Linuxはutf-8を使用する傾向があり、(おそらく)Windowsはcp1252を使用する傾向があります。

于 2010-05-18T02:39:36.570 に答える
4

「ハイアスキーキャラクター」というものはありません。ASCII文字セットは、範囲(128)の序数に制限されています。

それはさておき、これはFAQです。これが1つの答えです。一般に、str.translate()とunicode.translate()に精通している必要があります。これは、単一のバイト/文字を複数回置換する場合に非常に便利です。unicodedata.normalize()ギミックのみに言及している回答に注意してください。それはソリューションのほんの一部です。

更新:Mark Tolonenが指摘したように、現在受け入れられている回答は、分解されていない文字を吹き飛ばします。何unicode.translate()ができるのかについての知識が不足しているようです。1つの文字を複数の文字に変換できます。これがからの出力ですhelp(unicode.translate)

S.translate(table)-> unicode

文字列Sのコピーを返します。ここで、すべての文字は指定された変換テーブルを介してマッピングされています。これは、Unicode序数からUnicode序数、Unicode文字列、またはNoneへのマッピングである必要があります。マップされていない文字はそのまま残されます。Noneにマップされた文字は削除されます。

次に例を示します。

>>> u"Gau\xdf".translate({0xdf: u"ss"})
u'Gauss'
>>>

これが私が指摘したソリューションからの修正の表です:

CHAR_REPLACEMENT = {
    # latin-1 characters that don't have a unicode decomposition
    0xc6: u"AE", # LATIN CAPITAL LETTER AE
    0xd0: u"D",  # LATIN CAPITAL LETTER ETH
    0xd8: u"OE", # LATIN CAPITAL LETTER O WITH STROKE
    0xde: u"Th", # LATIN CAPITAL LETTER THORN
    0xdf: u"ss", # LATIN SMALL LETTER SHARP S
    0xe6: u"ae", # LATIN SMALL LETTER AE
    0xf0: u"d",  # LATIN SMALL LETTER ETH
    0xf8: u"oe", # LATIN SMALL LETTER O WITH STROKE
    0xfe: u"th", # LATIN SMALL LETTER THORN
    }

これは、cp1252および兄弟に見られる派手な引用符やその他の非latin-1文字に対応するために簡単に拡張できます。

于 2010-05-18T02:39:57.007 に答える
3

私はそれunicodedataが派手な引用にはうまくいかないと思います。Unidecodeこの場合、次を使用できます。

import unidecode
print unidecode.unidecode(u"ß‘’“”")
# -> ss''""
于 2010-05-20T19:02:22.747 に答える
1

によって提案されたunicodedata.normalize()がうまくいかない場合~unubtu、たとえば、マッピングをより細かく制御したい場合は、マップを作成するためのユーティリティであるstr.maketrans(

とともにstr.translate()を調べる必要があります。 table、str.translateは、このタイプの変換に効率的かつ便利です。 Python 2.xおよびUnicode文字列の場合、 str.translate()ではなくunicode.translate()を使用する必要があり、maketrans()の代わりに以下のコードスニペットに示すようなトリックを使用する必要があります。(これを指摘してくれたジョン・マチンに感謝します!)

これらのメソッドは、Python 3.xでも使用できます。たとえば、Python 3.1.2のドキュメントを参照してください (何らかの理由で、Python 3.xで変更された可能性があることに注意してください)。もちろん、Python 3では、すべての文字列はUnicode文字列ですが、それは別の問題です。

#Python 3.1
>>> intab = 'àâçêèéïîôù'
>>> outtab = 'aaceeeiiou'
>>> tmap = str.maketrans(intab, outtab)
>>> s = "à la fête de l'été, où il fait bon danser, les Français font les drôles"
>>> s
"à la fête de l'été, où il fait bon danser, les Français font les drôles"
>>> s.translate(tmap)
"a la fete de l'ete, ou il fait bon danser, les Francais font les droles"
>>>


#Python 2.6
>>> intab = u'àâçêèéïîôù'
>>> outtab = u'aaceeeiiou'
>>> s = u"à la fête de l'été, où il fait bon danser, les Français font les drôles"
>>> #note the trick to replace maketrans() since for unicode strings the translation
>>> #     map expects integers (unicode ordinals) not characters.
>>> tmap = dict(zip(map(ord, intab), map(ord, outtab))) 
>>> s.translate(tmap)
u"a la fete de l'ete, ou il fait bon danser, les Francais font les droles"
>>>
于 2010-05-18T02:40:06.333 に答える
0

latin-1文字を処理するソリューションは次のとおりです(2003年のusenetスレッドに基づく)。

>>> accentstable = str.join("", map(chr, range(192))) + "AAAAAAACEEEEIIIIDNOOOOOxOUUUUYTsaaaaaaaceeeeiiiidnooooo/ouuuuyty"
>>> import string
>>> s = u"éèêàùçÇ"
>>> print string.translate(s.encode('latin1', 'ignore'), accentstable)
eeeaucC

一部のマッピングは完全ではありません。たとえば、ThornはThではなくTにマップしますが、許容できる仕事をします。

于 2010-05-18T07:49:12.683 に答える