Pythonを使用して非ASCII文字を削除し、ピリオドとスペースを残すにはどうすればよいですか?


100

.txtファイルを使用しています。ASCII以外の文字を含まないファイルのテキスト文字列が必要です。ただし、スペースやピリオドは残したい。現在、私もそれらを取り除いています。これがコードです:

def onlyascii(char):
    if ord(char) < 48 or ord(char) > 127: return ''
    else: return char

def get_my_string(file_path):
    f=open(file_path,'r')
    data=f.read()
    f.close()
    filtered_data=filter(onlyascii, data)
    filtered_data = filtered_data.lower()
    return filtered_data

onlyascii()を変更してスペースとピリオドを残すにはどうすればよいですか?それほど複雑ではないと思いますが、理解できません。


ジョンの説明をありがとう(誠にありがとう)。スペースとピリオドはASCII文字であることを理解しました。ただし、ASCII以外の文字のみを削除しようとしたときに、意図せずに両方を削除していました。私の質問が他の方法でどのように暗示されたかがわかります。

@PoliticalEconomist:あなたの問題はまだ非常に詳細に指定されていません。私の答えを見てください。
John Machin、2011

回答:


187

次のように、string.printableを使用して、印刷できない文字列からすべての文字をフィルタリングできます。

>>> s = "some\x00string. with\x15 funny characters"
>>> import string
>>> printable = set(string.printable)
>>> filter(lambda x: x in printable, s)
'somestring. with funny characters'

私のマシンのstring.printableには以下が含まれます:

0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c

編集:Python 3では、フィルターはイテラブルを返します。文字列を戻す正しい方法は次のとおりです。

''.join(filter(lambda x: x in printable, s))

2
序数48未満の印刷可能な文字はどうなっていますか?
joaquin

38
使用の唯一の問題filterは、イテラブルを返すことです。文字列を戻す必要がある場合は(リスト圧縮を行うときにこれが必要だったために行ったように)、次のようにします''.join(filter(lambda x: x in string.printable, s)
cjbarth 2014

5
@cjbarth-コメントはpython 3固有ですが、非常に便利です。ありがとう!
undershock

7
正規表現を使用しないのはなぜですか re.sub(r'[^\x00-\x7f]',r'', your-non-ascii-string)。このスレッドを参照してくださいstackoverflow.com/a/20079244/658497
ノーム・マノス

1
@NoamManosこれは、結合...フィルタ...ラムダソリューションのおかげで、私にとって4〜5倍高速でした、ありがとうございます。
artfulrobot 2016

95

別のコーデックに変更する簡単な方法は、encode()またはdecode()を使用することです。あなたの場合、ASCIIに変換し、サポートされていないすべての記号を無視する必要があります。たとえば、スウェーデン語の文字åはASCII文字ではありません。

    >>>s = u'Good bye in Swedish is Hej d\xe5'
    >>>s = s.encode('ascii',errors='ignore')
    >>>print s
    Good bye in Swedish is Hej d

編集:

Python3:str->バイト-> str

>>>"Hej då".encode("ascii", errors="ignore").decode()
'hej d'

Python2:ユニコード-> str->ユニコード

>>> u"hej då".encode("ascii", errors="ignore").decode()
u'hej d'

Python2:str-> unicode-> str(逆順でデコードおよびエンコード)

>>> "hej d\xe5".decode("ascii", errors="ignore").encode()
'hej d'

16
私が得るUnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 27
Xodarap777 2014年

2
実際のユニコード文字をコピーアンドペーストで文字列に挿入すると、エラーが発生しました。u'thestring 'として文字列を指定すると、エンコードが正しく機能します。
Ben Liyanage、2015

2
Py3でのみ機能しますが、エレガントです。
過酷な

7
@ Xodarap777と同じエラーが発生する場合は、最初に文字列を.decode()し、その後にエンコードする必要があります。例s.decode('utf-8').encode('ascii', errors='ignore')
Spc_555 2017年

30

@artfulrobotによると、これはフィルターやラムダよりも速いはずです。

re.sub(r'[^\x00-\x7f]',r'', your-non-ascii-string) 

その他の例は、 http://stackoverflow.com/questions/20078816/replace-non-ascii-characters-with-a-single-space/20079244#20079244


1
この解決策はOPの述べられた質問に答えますが、私がOPが尋ねるつもりだったと私が思うASCIIに含まれている印刷できない文字を削除しないことに注意してください。
Danilo SouzaMorães18年

6

あなたの質問は曖昧です。一緒に取られた最初の2つの文は、スペースと「ピリオド」が非ASCII文字であると信じていることを意味します。これは誤りです。ord(char)<= 127のようなすべての文字はASCII文字です。たとえば、関数はこれらの文字! "#$%&\ '()* +、-。/を除外しますが、[] {}などの他の文字をいくつか含めます。

少し前に戻って少し考え、質問を編集して、ASCIIという単語に言及せずに何をしようとしているのか、また、ord(char)> = 128のような文字は無視できると思う理由を教えてください。また:Pythonのバージョンは?入力データのエンコーディングは何ですか?

コードは入力ファイル全体を単一の文字列として読み取り、別の回答へのコメント(「大きな解決策」)は、データの改行を気にしないことを意味することに注意してください。ファイルに次のような2行が含まれている場合:

this is line 1
this is line 2

結果は 'this is line 1this is line 2' ...あなたが本当に欲しいものですか?

より優れたソリューションには次のものがあります。

  1. フィルター関数のより良い名前 onlyascii
  2. 引数が保持される場合、フィルター関数は真の値を返すだけでよいという認識:

    def filter_func(char):
        return char == '\n' or 32 <= ord(char) <= 126
    # and later:
    filtered_data = filter(filter_func, data).lower()

この答えは、OPに似た質問をするためにやってきた私たちにとって非常に役立ちます。提案された答えは、役に立つPythonicです。しかし、私が(私がよく遭遇する)問題を解釈すると、問題に対するより効率的な解決策がないというのは奇妙なことです。
Xodarap777 2014年

5

次のコードを使用して、英語以外の文字を削除できます。

import re
str = "123456790 ABC#%? .(朱惠英)"
result = re.sub(r'[^\x00-\x7f]',r'', str)
print(result)

これは戻ります

123456790 ABC#%?。()


1

印刷可能なASCII文字が必要な場合は、コードを次のように修正する必要があります。

if ord(char) < 32 or ord(char) > 126: return ''

これはstring.printable(@jterraceからの回答)と同じですが、リターンとタブ( '\ t'、 '\ n'、 '\ x0b'、 '\ x0c'および '\ r')がないことを除いて、あなたの質問の範囲


1
少し簡単:ラムダx:32 <= ord(x)<= 126
jterrace

これはstring.printableとは異なります。これはstring.whitespaceが省略されるためです。OPが必要とするものである可能性がありますが、\ nや\ tなどに依存します。
jterrace

@jterrace右、スペース(ord 32)が含まれますが、リターンとタブは含まれません
joaquin

ええ、「これはstring.printableと同等です」とコメントするだけですが、真実ではありません
jterrace

回答を編集しました、ありがとう!OPの質問は、注意深く読まないと誤解を招く恐れがあります。
ホアキン

1

Fluent Python(Ramalho)での作業-強くお勧めします。第2章に触発された理解力のある一言一言:

onlyascii = ''.join([s for s in data if ord(s) < 127])
onlymatch = ''.join([s for s in data if s in
              'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'])

これは、箇条書き、度記号、著作権記号、円記号などの標準のASCII記号を許可しません。また、最初の例には、BELLなどの印刷できない記号が含まれていますが、これは望ましくありません。
SherylHohman
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.