web-dev-qa-db-ja.com

悪い文字を効率的に置き換える

私はよく以下のような文字を含むutf-8テキストを扱います:

\ xc2\x99

\ xc2\x95

\ xc2\x85

これらの文字は、使用している他のライブラリを混乱させるため、置き換える必要があります。

これを行うための効率的な方法は何ですか?

text.replace('\xc2\x99', ' ').replace('\xc2\x85, '...')
24
hoju

常に正規表現があります。次のように、角かっこ内に問題のある文字をすべてリストします。

import re
print re.sub(r'[\xc2\x99]'," ","Hello\xc2There\x99")

これは、「Hello There」と印刷し、不要な文字をスペースで置き換えます。

または、それぞれに異なる置換文字がある場合:

# remove annoying characters
chars = {
    '\xc2\x82' : ',',        # High code comma
    '\xc2\x84' : ',,',       # High code double comma
    '\xc2\x85' : '...',      # Tripple dot
    '\xc2\x88' : '^',        # High carat
    '\xc2\x91' : '\x27',     # Forward single quote
    '\xc2\x92' : '\x27',     # Reverse single quote
    '\xc2\x93' : '\x22',     # Forward double quote
    '\xc2\x94' : '\x22',     # Reverse double quote
    '\xc2\x95' : ' ',
    '\xc2\x96' : '-',        # High hyphen
    '\xc2\x97' : '--',       # Double hyphen
    '\xc2\x99' : ' ',
    '\xc2\xa0' : ' ',
    '\xc2\xa6' : '|',        # Split vertical bar
    '\xc2\xab' : '<<',       # Double less than
    '\xc2\xbb' : '>>',       # Double greater than
    '\xc2\xbc' : '1/4',      # one quarter
    '\xc2\xbd' : '1/2',      # one half
    '\xc2\xbe' : '3/4',      # three quarters
    '\xca\xbf' : '\x27',     # c-single quote
    '\xcc\xa8' : '',         # modifier - under curve
    '\xcc\xb1' : ''          # modifier - under line
}
def replace_chars(match):
    char = match.group(0)
    return chars[char]
return re.sub('(' + '|'.join(chars.keys()) + ')', replace_chars, text)
35
Nate

ここには根本的な問題があると思います。症状を隠蔽するだけでなく、調査して解決することをお勧めします。

\xc2\x95は、文字U + 0095のUTF-8エンコードです。これは C1制御文字 (メッセージ待ち)です。ライブラリがそれを処理できないのは当然のことです。しかし、問題は、それがどのようにしてデータに取り込まれたのかということです。

まあ、1つの可能性が高いのは、 Windows-1252 エンコーディングの文字0x95(BULLET)として開始され、正しいU + 2022ではなくU + 0095として誤ってデコードされ、その後エンコードされた可能性があります。 UTF-8に。 (日本語の用語 mojibake はこの種の間違いを説明しています。)

これが正しい場合は、元の文字をWindows-1252に戻して、今回は正しくUnicodeにデコードすることにより、元の文字を復元できます。 (これらの例では、Python 3.3を使用しています。これらの演算は、Python 2.で少し異なります。)

>>> b'\x95'.decode('windows-1252')
'\u2022'
>>> import unicodedata
>>> unicodedata.name(_)
'BULLET'

有効なWindows-1252文字である0x80〜0x99の範囲のすべての文字に対してこの修正を行う場合は、次の方法を使用できます。

def restore_windows_1252_characters(s):
    """Replace C1 control characters in the Unicode string s by the
    characters at the corresponding code points in Windows-1252,
    where possible.

    """
    import re
    def to_windows_1252(match):
        try:
            return bytes([ord(match.group(0))]).decode('windows-1252')
        except UnicodeDecodeError:
            # No character at the corresponding code point: remove it.
            return ''
    return re.sub(r'[\u0080-\u0099]', to_windows_1252, s)

例えば:

>>> restore_windows_1252_characters('\x95\x99\x85')
'•™…'
23
Gareth Rees

文字列からすべての非ASCII文字を削除する場合は、次を使用できます。

text.encode("ascii", "ignore")
11
Tim Pietzcker
import unicodedata

# Convert to unicode
text_to_uncicode = unicode(text, "utf-8")           

# Convert back to ascii
text_fixed = unicodedata.normalize('NFKD',text_to_unicode).encode('ascii','ignore')         
2
Ady

これは「Unicode文字」ではなく、UTF-8でエンコードされた文字列に似ています。 (ただし、ほとんどの文字では\ xC2ではなく、\ xC3にする必要があります)。あなたはすべきではないCOBOLバックエンドと通信しているのでない限り、95%のケースでそれらを捨てるだけです。世界は26文字に制限されていません。

Unicode文字列の違いを説明する簡潔な読みがあります(python 2でUnicodeオブジェクトとして使用され、Python 3の文字列としてここで使用されるもの:- http://www.joelonsoftware.com/articles/Unicode.html -お読みください。すべてのアプリケーションで英語以外のものを使用する予定がない場合でも、それでも、7ビットASCIIに収まらない€やsymbolsのような記号に出くわすでしょうが、その記事が役立ちます。

とは言っても、使用しているライブラリはUnicode pythonオブジェクトを受け入れ、UTF-8 Python 2の文字列をunidoceに変換することにより、

var_unicode = var.decode("utf-8")

本当に100%純粋なASCIIが必要な場合は、すべての非ASCII chars、afterを置き換えて文字列をユニコードにデコードし、re -それをASCIIにエンコードし、文字セットに適合しない文字を無視するように指示します:

var_ascii = var_unicode.encode("ascii", "replace")
0
jsbueno

これらの文字はASCIIライブラリに含まれていないため、エラーが発生します。これらのエラーを回避するには、ファイルの読み取り中に次の操作を実行します。

import codecs   
f = codecs.open('file.txt', 'r',encoding='utf-8')

これらの種類のエラーの詳細については、 このリンク を参照してください。

0