Unicodeテキストをテキストファイルに書き込みますか?


225

Googleドキュメントからデータを引き出して処理し、ファイルに書き込みます(最終的にはWordpressページに貼り付けます)。

いくつかの非ASCIIシンボルがあります。これらをHTMLソースで使用できるシンボルに安全に変換するにはどうすればよいですか?

現在、私は途中ですべてをUnicodeに変換し、それをすべてPython文字列に結合してから、次のようにしています:

import codecs
f = codecs.open('out.txt', mode="w", encoding="iso-8859-1")
f.write(all_html.encode("iso-8859-1", "replace"))

最終行にエンコードエラーがあります:

UnicodeDecodeError: 'ascii'コーデックは位置12286のバイト0xa0をデコードできません:序数が範囲(128)にありません

部分的な解決策:

このPythonはエラーなしで実行されます。

row = [unicode(x.strip()) if x is not None else u'' for x in row]
all_html = row[0] + "<br/>" + row[1]
f = open('out.txt', 'w')
f.write(all_html.encode("utf-8"))

しかし、実際のテキストファイルを開くと、次のような多くの記号が表示されます。

Qur’an 

テキストファイル以外のものに書き込む必要があるのでしょうか。


1
それを開くために使用しているプログラムは、UTF-8テキストを正しく解釈していません。ファイルをUTF-8として開くオプションが必要です。
トーマスK

回答:


322

最初にオブジェクトを取得するときに、オブジェクトをUnicodeオブジェクトにデコードし、途中で必要に応じてエンコードすることにより、Unicodeオブジェクトを可能な限り排他的に処理します。

文字列が実際にUnicodeオブジェクトである場合は、ファイルに書き込む前に、Unicodeエンコードされた文字列オブジェクトに変換する必要があります。

foo = u'Δ, Й, ק, ‎ م, ๗, あ, 叶, 葉, and 말.'
f = open('test', 'w')
f.write(foo.encode('utf8'))
f.close()

そのファイルを再度読み取ると、Unicodeエンコードされた文字列が得られ、Unicodeオブジェクトにデコードできます。

f = file('test', 'r')
print f.read().decode('utf8')

ありがとう。これはエラーなしで実行されますが、テキストファイルを開くと、奇妙な記号がたくさん表示されます。:)テキストをコピーしてWordpressページに貼り付ける必要があります(質問しないでください)。そこにあるシンボルを実際に印刷する方法はありますか?たぶん、txtファイルではなく、他の何かでしょうか?
サイモン、

1
テキストファイルを開くために何を使用していますか?あなたがWindowsを使用していて、それをメモ帳で開いていると思います。これは、エンコーディングに関してはあまりインテリジェントではありません。ワードパッドで開くとどうなりますか?
準静的、2011年

@quasistoic fileメソッドはどこから来るのですか?
Omar Cusma Fait

stackoverflow.com/a/5513856/6580199で説明されているように、バイナリモードをオンにする必要があります。つまり、f = open( 'test'、 'wb')です。そうしないと、「TypeError:write()引数はstrでなければなりません。バイトではない」
ベンジー

72

Python 2.6以降では、Python 3のデフォルト(組み込み)を使用io.open()できますopen()

import io

with io.open(filename, 'w', encoding=character_encoding) as file:
    file.write(unicode_text)

テキストをインクリメンタルに書き込む必要がある場合(unicode_text.encode(character_encoding)複数回呼び出す必要がない場合)は、より便利な場合があります。codecsモジュールとは異なり、ioモジュールは適切なユニバーサル改行をサポートしています。


1
男、私はこれを見つけるのに多くの時間を費やしました!ありがとうございました!
Georgy Gobozov 2018

2
これはPython 3でも機能します(明白ですが、指摘する価値があります)。
カバ

37

Unicode文字列の処理はPython 3ですでに標準化されています。

  1. charはすでにメモリ内のUnicode(32ビット)に格納されています
  2. utf-8でファイルを開くだけで済みます
    (32ビットUnicodeから可変バイト長のutf-8への変換は、メモリからファイルに自動的に実行されます)。

    out1 = "(嘉南大圳 ㄐㄧㄚ ㄋㄢˊ ㄉㄚˋ ㄗㄨㄣˋ )"
    fobj = open("t1.txt", "w", encoding="utf-8")
    fobj.write(out1)
    fobj.close()
    

しかし、これはPython 2では機能しませんよね?(私は言って
おき

Python 2では動作しないはずです。Python3のままです。3の方がはるかに優れています。
david m lee 2017年

18

によって開かれcodecs.openたファイルは、unicodeデータを受け取り、エンコードiso-8859-1して、ファイルに書き込むファイルです。しかし、あなたが書こうとしているのはそうではありませんunicode。あなたはunicodeそれをiso-8859-1 自分で受け取り、エンコードします。これがunicode.encodeメソッドの機能であり、Unicode文字列をエンコードした結果はバイト文字列(str型)です。

通常open()を使用して自分でUnicodeをエンコードするか、(通常はより良いアイデア)データを自分でエンコードして使用codecs.open()ないでください。


17

序文:ビューアは機能しますか?

ビューア/エディタ/ターミナル(utf-8でエンコードされたファイルを操作している場合でも)がファイルを読み取れることを確認してください。これは、メモ帳などのWindowsでよく発生する問題です。

Unicodeテキストをテキストファイルに書き込みますか?

Python 2ではopenioモジュールから使用します(これはopenPython 3の組み込みと同じです):

import io

一般的に、UTF-8ファイルへの書き込みにはベストプラクティスを使用します(utf-8を使用してバイト順を気にする必要もありません)。

encoding = 'utf-8'

utf-8は最もモダンで普遍的に使用できるエンコーディングです。すべてのWebブラウザー、ほとんどのテキストエディター(問題がある場合は設定を参照)、ほとんどのターミナル/シェルで動作します。

Windowsでは、utf-16leメモ帳(または別の制限されたビューアー)での出力の表示に制限されている場合に試すことができます。

encoding = 'utf-16le' # sorry, Windows users... :(

コンテキストマネージャーで開き、Unicode文字を書き出します。

with io.open(filename, 'w', encoding=encoding) as f:
    f.write(unicode_object)

多くのUnicode文字を使用した例

次の例では、デジタル表示(整数)からエンコードされた印刷可能な出力に、最大3ビット幅(4が最大ですが、少し遠くまで行く可能性があります)のすべての可能な文字を、その名前と一緒にマッピングします。可能(これをと呼ばれるファイルに入れますuni.py):

from __future__ import print_function
import io
from unicodedata import name, category
from curses.ascii import controlnames
from collections import Counter

try: # use these if Python 2
    unicode_chr, range = unichr, xrange
except NameError: # Python 3
    unicode_chr = chr

exclude_categories = set(('Co', 'Cn'))
counts = Counter()
control_names = dict(enumerate(controlnames))
with io.open('unidata', 'w', encoding='utf-8') as f:
    for x in range((2**8)**3): 
        try:
            char = unicode_chr(x)
        except ValueError:
            continue # can't map to unicode, try next x
        cat = category(char)
        counts.update((cat,))
        if cat in exclude_categories:
            continue # get rid of noise & greatly shorten result file
        try:
            uname = name(char)
        except ValueError: # probably control character, don't use actual
            uname = control_names.get(x, '')
            f.write(u'{0:>6x} {1}    {2}\n'.format(x, cat, uname))
        else:
            f.write(u'{0:>6x} {1}  {2}  {3}\n'.format(x, cat, char, uname))
# may as well describe the types we logged.
for cat, count in counts.items():
    print('{0} chars of category, {1}'.format(count, cat))

これは約1分程度で実行され、データファイルを表示できます。ファイルビューアでUnicodeを表示できる場合は、Unicodeが表示されます。カテゴリーについての情報はここにあります。カウントに基づいて、シンボルが関連付けられていないCnおよびCoカテゴリを除外することで、結果を改善できると考えられます。

$ python uni.py

16進数のマッピング、カテゴリ、シンボル(名前を取得できない場合は、おそらく制御文字)、およびシンボルの名前が表示されます。例えば

lessはUnixまたはCygwin をお勧めします(出力全体にファイル全体を出力または出力しないでください)。

$ less unidata

たとえば、Python 2(Unicode 5.2)を使用してサンプリングした次のような行が表示されます。

     0 Cc NUL
    20 Zs     SPACE
    21 Po  !  EXCLAMATION MARK
    b6 So    PILCROW SIGN
    d0 Lu  Ð  LATIN CAPITAL LETTER ETH
   e59 Nd    THAI DIGIT NINE
  2887 So    BRAILLE PATTERN DOTS-1238
  bc13 Lo    HANGUL SYLLABLE MIH
  ffeb Sm    HALFWIDTH RIGHTWARDS ARROW

私のAnacondaのPython 3.5はunicode 8.0を持っています。ほとんどの3がそうだと思います。


3

Unicode文字をファイルに出力する方法:

これをファイルに保存します:foo.py:

#!/usr/bin/python -tt
# -*- coding: utf-8 -*-
import codecs
import sys 
UTF8Writer = codecs.getwriter('utf8')
sys.stdout = UTF8Writer(sys.stdout)
print(u'e with obfuscation: é')

それを実行し、出力をファイルにパイプします。

python foo.py > tmp.txt

tmp.txtを開いて中を見ると、次のようになっています。

el@apollo:~$ cat tmp.txt 
e with obfuscation: é

したがって、難読化マークが付いたUnicode eをファイルに保存しました。


2
私はこの答えにかなり興奮していましたが、私のマシンでエラーが発生しました。コードをコピーして貼り付けると、「TypeError:バイトではなくstrでなければならない」というエラーが表示されます
Richard Rast

1

このエラーは、非Unicode文字列をエンコードしようとすると発生します。プレーンASCIIであると想定して、デコードしようとします。2つの可能性があります。

  1. バイト文字列にエンコードしていますが、codecs.openを使用したため、writeメソッドはUnicodeオブジェクトを想定しています。だからあなたはそれをエンコードし、それはそれを再びデコードしようとします。f.write(all_html)代わりに試してください。
  2. all_htmlは、実際には、Unicodeオブジェクトではありません。実行すると.encode(...)、最初にそれをデコードしようとします。

0

python3で書く場合

>>> a = u'bats\u00E0'
>>> print a
batsà
>>> f = open("/tmp/test", "w")
>>> f.write(a)
>>> f.close()
>>> data = open("/tmp/test").read()
>>> data
'batsà'

python2で書く場合:

>>> a = u'bats\u00E0'
>>> f = open("/tmp/test", "w")
>>> f.write(a)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)

このエラーを回避するには、次のようにコーデック「utf-8」を使用してバイトにエンコードする必要があります。

>>> f.write(a.encode("utf-8"))
>>> f.close()

コーデック「utf-8」を使用して読み取り中にデータをデコードします。

>>> data = open("/tmp/test").read()
>>> data.decode("utf-8")
u'bats\xe0'

また、この文字列に対して印刷を実行しようとすると、このような「utf-8」コーデックを使用して自動的にデコードされます

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