2013-06-24 3 views
7

PythonのUTF-8エンコーディング(codecsパッケージ)は、Unicode文字28,29、および30を行末として解釈します。どうして?そして、どうしたらそれを防ぐことができますか?Pythonコーデックの行末

例コード:

with open('unicodetest.txt', 'w') as f: 
    f.write('a'+chr(28)+'b'+chr(29)+'c'+chr(30)+'d'+chr(31)+'e') 
with open('unicodetest.txt', 'r') as f: 
    for i,l in enumerate(f): 
    print i, l 
# prints "0 abcde" with special characters in between. 

ここでのポイントは、私はそれが何を期待するとして、それは1行としてそれを読み込むことです。今私がcodecsを使ってUTF-8で読むと、それはそれを多くの行として解釈します。

import codecs 
with codecs.open('unicodetest.txt', 'r', 'UTF-8') as f: 
    for i,l in enumerate(f): 
    print i, l 
# 0 a 
# 1 b 
# 2 c 
# 3 de 
# (again with the special characters after each a, b, c, d 

文字「28」から「31」は、「情報セパレータ4」から「1」(その順番)と記載されています。 2つのことが私に打撃を与えます:1)28〜30は行末として解釈され、2)31はそうではありません。これは意図された動作ですか?行末として解釈される文字の定義はどこで見つけることができますか?行末として解釈しない方法はありますか?

ありがとうございました。

codecs.openに 'UTF-8'引数をコピーするのを忘れました。私の質問のコードが修正されました。

+0

ファイルを 'rb 'モードで開くとどうなりますか? – unutbu

+0

違いはありません。 – Paul

+2

@Paul、あなたは自分の質問に答えることができ、あなたが好きならそれを受け入れることができます –

答えて

5

これは大きな質問です。

open()またはcodecs.open()のファイルを開くかどうかは異なります。前者はバイト文字列で動作します。後者はUnicode文字列で動作します。 Pythonでは、これらはbehave differentlyです。

この同じ質問はPython Issue 7643, What is a Unicode line break character?となりました。議論、そしてUnicode Character Databaseへの引用は魅力的です。発行7643はまた違いを実証するために、この簡潔なコードスニペットいます:

for s in '\x0a\x0d\x1c\x1d\x1e': 
    print u'a{}b'.format(s).splitlines(1), 'a{}b'.format(s).splitlines(1) 

をしかし、それはこれに沸きます。

バイト文字列のバイトが改行(または空白)かどうかを判断するには、PythonはASCII control charactersの規則を使用します。その尺度では、バイト10と13は改行文字です(そして、Pythonはバイト13の後に10を1行の改行として扱います)。

しかし、Unicode文字列の文字が改行されているかどうかを判断するために、PythonはUAX #44で文書化され、Unicode Character Databaseの文字分類に従い、UAX #14 Line Breaking Algorithm, section 5 Line Breaking Propertiesの。

  • 一般カテゴリーZ1の「行区切り」
  • 一般カテゴリーZpの「段落区切り」
  • 双方向クラス:発行7643によると、これらのドキュメントは、Pythonの目的のために改行として文字を識別する3つの文字プロパティを識別しますB「段落区切り記号」

文字28(0x001C)、29(0x001D)、および30(0x001E)にはこれらの文字プロパティがあります。文字31(0x001F)はありません。どうして?これはUnicode技術委員会の質問です。しかしASCIIでは、これらの文字は「ファイルセパレータ」、「グループセパレータ」、「レコードセパレータ」、および「ユニットセパレータ」として知られていました。タブ付きのテキストデータファイルを比較として使用すると、最初の3つは少なくとも改行と同じくらいの分離を意味し、4つ目はおそらくタブに類似しています。

実際にこれら3つのUnicode文字をPython Unicode文字列の改行として定義しているコードはObjects/unicodeobject.cです。配列ascii_linebreak[]を探してください。この配列はunicode.splitlines()の実装に基づいています。異なるコードの基礎はstr.splitlines()です。私は信じていますが、Pythonのソースコードでは、codecs.open()で開かれたファイルのenumerate()は、というユニコードで実装されています。.splitlines()

「どうすればいいのですか?」 splitlines()の動作が異なるようには見えません。

with open('unicodetest.txt', 'r') as f: 
    for i,l in enumerate(f): 
    print i, l.decode('UTF-8') 
# prints "0 abcde" with special characters in between. 

私はあなたがPythonの2を使用していると仮定します。しかし、あなたはstr.splitlines()行動にバイトとしてラインを読み、バイトストリームとしてファイルを開くことができ、その後、Unicode文字列として使用するためにUTF-8などの各ラインをデコード.x、3.xではなく.x私の答えはPython 2.7に基づいています。

+1

ありがとう。これは精巧です。そして、あなたのソリューションに感謝します。意味をなさない – Paul

関連する問題