web-dev-qa-db-ja.com

テキストファイルへのUnicodeテキストの書き込み

私は、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 

たぶん私はテキストファイル以外の何かに書く必要がありますか?

210
simon

Unicodeオブジェクトを最初に入手したときにそれらを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')
303
quasistoic

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モジュールは適切なユニバーサル改行をサポートしています。

63
jfs

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

  1. CharはUnicodeで格納されています
  2. あなただけのutf-8でファイルを開く必要があります

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

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

通常のopen()を使って自分でUnicodeをエンコードするか、(通常はcodecs.open()を使ってnot自分でデータをエンコードする)べきです。

18
Thomas Wouters

序文:あなたの視聴者は動くでしょうか?

あなたのビューア/エディタ/端末(しかしあなたがあなたのutf-8でエンコードされたファイルと対話している)がファイルを読むことができることを確認してください。これは、 Windows (たとえばメモ帳)で頻繁に問題になります。

テキストファイルへのUnicodeテキストの書き込み

Python 2では、openモジュールのioを使用します(これはPython 3の組み込みのopenと同じです)。

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が表示される場合は、それが表示されます。カテゴリに関する情報は こちら で見つけることができます。カウントに基づいて、シンボルが関連付けられていないCnカテゴリとCoカテゴリを除外することで、おそらく結果を改善できます。

$ python uni.py

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

私はUnixやCygwinでlessを使うことをお勧めします(ファイル全体をあなたの出力に表示したり/出力しないでください):

$ 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はユニコード8.0を持っています、私はほとんどの3がすると思います。

14
Aaron Hall

ファイルに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をファイルに保存しました。

3
Eric Leschinski

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

  1. これをバイト文字列にエンコードしていますが、codecs.openを使用しているので、writeメソッドにはUnicodeオブジェクトが必要です。だからあなたはそれをエンコードし、それはそれをもう一度デコードしようとします。代わりにf.write(all_html)をお試しください。
  2. all_htmlは、実際には、Unicodeオブジェクトではありません。 .encode(...)を実行すると、まずそれをデコードしようとします。
1
Thomas K

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'

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

>>> print a
batsà
0
ashish14