Pythonインタプリタに文字列操作で非ASCII文字を正しく処理させるにはどうすればよいですか?


104

次のような文字列があります。

6 918 417 712

この文字列をトリミングする明確な方法(Pythonを理解しているように)は、文字列がと呼ばれる変数にあると言うだけsです。

s.replace('Â ', '')

これでうまくいくはずです。しかしもちろん、'\xc2'blabla.pyファイル内の非ASCII文字がエンコードされていないことを訴えます。

異なるエンコーディングを切り替える方法を私はまったく理解できませんでした。

ここにコードがあります、それは実際には上記と同じですが、今はコンテキストにあります。ファイルはメモ帳でUTF-8として保存され、次のヘッダーがあります。

#!/usr/bin/python2.4
# -*- coding: utf-8 -*-

コード:

f = urllib.urlopen(url)

soup = BeautifulSoup(f)

s = soup.find('div', {'id':'main_count'})

#making a print 's' here goes well. it shows 6Â 918Â 417Â 712

s.replace('Â ','')

save_main_count(s)

それ以上のことはありませんs.replace...


1
これまでに4つの回答すべてを試しました。立ち入り禁止。それでもUnicodeDecodeErrorが発生する: 'ascii'コーデックは位置1のバイト0xc2をデコードできません:序数が範囲外です(128)
adergaard

ユニコード文字列の先頭に追加する必要ありますu
SilentGhost

@SilentGhost:ご覧のとおり、Unicode文字列であることを確認する方法はありません。上記の内容の文字列を取得しましたが、非ASCII文字列が含まれています。それが本当の問題です。私はそれが最初の128ではないので、それはユニコードで推測している
adergaard

エラーは着信文字列とは関係ありません。このエラーが発生するのは、コード内の文字列です!
SilentGhost 2009

2
このような混乱を避けるために、Python 3が文字列とバイトシーケンスの違いについて非常に厳しいのはこのためです。
マークランサム

回答:


84

Python 2はasciiソースファイルのデフォルトエンコーディングとして使用します。つまり、リテラルで非ASCII Unicode文字を使用するには、ファイルの先頭で別のエンコーディングを指定する必要があります。Python 3はutf-8ソースファイルのデフォルトエンコーディングとして使用するため、これはそれほど問題ではありません。

参照:http : //docs.python.org/tutorial/interpreter.html#source-code-encoding

utf-8ソースエンコーディングを有効にするには、これは上の2行のうちの1行になります。

# -*- coding: utf-8 -*-

上記はドキュメントにありますが、これも機能します:

# coding: utf-8

その他の考慮事項:

  • ソースファイルは、テキストエディタでも正しいエンコーディングを使用して保存する必要があります。

  • Python 2では、Unicodeリテラルはそのu前にある必要がありs.replace(u"Â ", u"")ます。ただし、Python 3では、引用符を使用します。Python 2ではfrom __future__ import unicode_literals、Python 3の動作を取得できますが、これは現在のモジュール全体に影響することに注意してください。

  • s.replace(u"Â ", u"")sUnicode文字列でない場合も失敗します。

  • string.replace 新しい文字列を返し、その場で編集しないため、戻り値も使用していることを確認してください


4
実際に必要なのはだけです# coding: utf-8-*-装飾用ではありませんが、必要になることはほとんどありません。古い砲弾があったと思います。
fmalina 2013年

157
def removeNonAscii(s): return "".join(filter(lambda x: ord(x)<128, s))

編集:私の最初の衝動は常にフィルターを使用することですが、ジェネレーター式はよりメモリ効率が良い(そして短い)...

def removeNonAscii(s): return "".join(i for i in s if ord(i)<128)

これはUTF-8エンコーディングでの動作が保証されていることに注意してください(マルチバイト文字のすべてのバイトの最上位ビットが1に設定されているため)。


1
TypeError:ord()は文字を期待していましたが、長さ2の文字列が見つかりました
Ivelin

@Ivelinこれは、「文字」が適切なUnicodeとして解釈されていないためです... uリテラルの場合、ソース文字列の前にプレフィックスが付いていることを確認してください。
Fortran、2013年

35
>>> unicode_string = u"hello aåbäcö"
>>> unicode_string.encode("ascii", "ignore")
'hello abc'

4
私はあなたが得る投票を見ますが、私がそれを試すときそれは言う:いいえ。UnicodeDecodeError: 'ascii'コーデックは位置1のバイト0xc2をデコードできません:序数が範囲(128)にありません。私の元の文字列がユニコードではないのでしょうか?いずれにせよ。必要
アデルガード09

2
よかった、ありがとう。結果に.decode()を使用して元のコーディングで取得することをお勧めできますか?
AkiRoss

UnicodeDecodeError: 'ascii'が発生する場合は、エンコード関数を適用する前に、文字列を '' UTF-8 '形式に変換してみてください。
Sateesh

16

次のコードは、すべての非ASCII文字を疑問符で置き換えます。

"".join([x if ord(x) < 128 else '?' for x in s])

好奇心から知りたいのですが、疑問符に置き換える特別な理由はありますか?
Mohsin 2017年

6

正規表現の使用:

import re

strip_unicode = re.compile("([^-_a-zA-Z0-9!@#%&=,/'\";:~`\$\^\*\(\)\+\[\]\.\{\}\|\?\<\>\\]+|[^\s]+)")
print strip_unicode.sub('', u'6Â 918Â 417Â 712')

5

回答には遅すぎますが、元の文字列はUTF-8であり、 '\ xc2 \ xa0'はNO-BREAK SPACEのUTF-8です。元の文字列を次のようにデコードするだけですs.decode('utf-8')ます。Windows-1252またはラテン-1として誤ってデコードされた空間として\ XA0が表示されます(

例(Python 3)

s = b'6\xc2\xa0918\xc2\xa0417\xc2\xa0712'
print(s.decode('latin-1')) # incorrectly decoded
u = s.decode('utf8') # correctly decoded
print(u)
print(u.replace('\N{NO-BREAK SPACE}','_'))
print(u.replace('\xa0','-')) # \xa0 is Unicode for NO-BREAK SPACE

出力

6 918 417 712
6 918 417 712
6_918_417_712
6-918-417-712

3
#!/usr/bin/env python
# -*- coding: utf-8 -*-

s = u"6Â 918Â 417Â 712"
s = s.replace(u"Â", "") 
print s

これは印刷されます 6 918 417 712


いいえ。UnicodeDecodeError: 'ascii'コーデックは位置1のバイト0xc2をデコードできません:序数が範囲(128)にありません。私の元の文字列がユニコードではないのでしょうか?いずれにせよ。私はおそらく何か間違ったことをしています。
アデルガード、2009

@adergaard、ソースファイルの先頭に#-- コーディング:utf- 8--を追加しましたか?
Nadia Alramli、2009

はい、このページの上部をもう一度参照してください。クエストインを編集し、コードとヘッダーコメントを追加しました。ご協力ありがとうございます。
アデルガード、2009

Unicodeでhtmlまたはxmlドキュメントから文字列を取得する方法を理解する必要があると思います。その詳細はこちら:diveintopython.org/xml_processing/unicode.html
Isaiah

2

私はそれが古いスレッドであることを知っていますが、128を超えるすべての文字コード(または必要に応じて他の文字コード)を置き換えるための常に良い方法である変換方法について言及せざるを得ませんでした。

使用法:str。変換table [、deletechars]

>>> trans_table = ''.join( [chr(i) for i in range(128)] + [' '] * 128 )

>>> 'Résultat'.translate(trans_table)
'R sultat'
>>> '6Â 918Â 417Â 712'.translate(trans_table)
'6  918  417  712'

以降ではPython 2.6、あなたもなしにテーブルを設定し、使用できるのdeletecharsをで標準ドキュメントに示す例のように、あなたがしたくない文字を削除しhttp://docs.python.org/library/stdtypes。 html

ユニコード文字列では、変換テーブルは256文字の文字列ではなく、関連する文字のord()をキーとして持つ辞書です。しかし、とにかく、ユニコード文字列から適切なASCII文字列を取得することは、上記のtruppoによって言及されたメソッドを使用して十分簡単です。すなわち、unicode_string.encode( "ascii"、 "ignore")

要約すると、何らかの理由でASCII文字列を取得する必要がある場合(たとえば、標準の例外をで発生させる場合raise Exception, ascii_message)、次の関数を使用できます。

trans_table = ''.join( [chr(i) for i in range(128)] + ['?'] * 128 )
def ascii(s):
    if isinstance(s, unicode):
        return s.encode('ascii', 'replace')
    else:
        return s.translate(trans_table)

翻訳の良いところは、アクセント付き文字を実際に変換できることです 単に削除したり「?」で置き換える代わりに、アクセント関連する非アクセント付きASCII文字にです。これは、インデックス作成などの目的でしばしば役立ちます。


取得:TypeError:文字マッピングは整数、Noneまたはunicodeを返す必要があります
Ivelin 2013年


1

これは汚いハックですが、うまくいくかもしれません。

s2 = ""
for i in s:
    if ord(i) < 128:
        s2 += i

0

価値があるのは、私のキャラクターセットでした。utf-8クラシックな " # -*- coding: utf-8 -*-"行も含めました。

しかし、ウェブページからこのデータを読んだときに、ユニバーサルニューラインがないことがわかりました。

テキストに「\r\n」で区切られた2つの単語が含まれていました。で分割して\n交換しただけ"\n"です。

ループして問題の文字セットを見ると、間違いに気付きました。

つまり、ASCII文字セット内にある可能性もありますが、予想外の文字です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.