3

たとえば、Python では次のようになります。

f = open('test','w')
f.write('this is a test\n'.encode('utf-16'))
f.write('another test\n'.encode('utf-8'))
f.close()

もう一度開くと、そのファイルは乱雑になります。

f = open("test")
print f.readline().decode('utf-16')  # it leads to UnicodeDecodeError
print f.readline().decode('utf-8')   # it works fine

ただし、テキストを 1 つのスタイル (たとえば utf-16 のみ) でエンコードしたままにしておくと、問題なく読み取ることができます。したがって、特定の各文字列のエンコード規則を知っていても、同じファイルに 2 種類のエンコードを混在させるのは間違っていて、デコードできなかったのではないでしょうか? どんな提案でも大歓迎です、ありがとう!

4

4 に答える 4

5

これは通常は悪い考えですが、あなたの場合は改行もエンコードするため機能しません。

UTF-16 では、書き込んだ改行を含め、すべての文字が 2 バイトにエンコードされます。ファイルを 1 行ずつ読み取るため、Python はファイルから次の改行バイトまでのすべてのデータを提供しますが、UTF-16 では、返されたデータに 2 バイトのうちの 1 つがまだ含まれている可能性があり、結果として不完全になります。 UTF-16 バイト ストリーム。

これを理解するには、UTF-16 エンコーディングをより詳細に理解する必要があります。16 ビット データを 8 ビットの 2 バイトとして書き込む場合、コンピューターは最初にファイルに書き込むバイトを決定する必要があります。この決定は 2 つの方法で行うことができ、エンディアンと呼ばれます。ガリバーのリリパットのように、コンピュータ システムはビッグ エンディアンまたはリトル エンディアンのいずれかを優先します。

したがって、UTF-16 データ ストリームは 2 つの順序のいずれかで書き込まれ、どちらが選択されたかを示すためにバイト オーダー マークまたは「BOM」が最初に書き込まれます。

'\n\x00'したがって、改行はまたはとしてエンコードされ'\x00\n'、ヌルバイト ( ) を読み取ると、\x00デコードする UTF-16 データの一部か、UTF-8 データ (無視される場合) のいずれかになります。したがって、UTF-16 をビッグ エンディアンとしてエンコードするとうまくいきますが (ただし、ヌル バイトが浮遊します)、リトル エンディアンとしてエンコードするとうまくいきません。

基本的に、エンコードされたデータは厳密にバイナリ データとして扱われる必要があり、別の方法を使用してエンコードされたテキストのさまざまな部分を記述する、改行が改行として厳密にエンコードされるエンコーディングのみを使用する必要があります。

長さのプレフィックスを使用し、最初にそれを読み取り、次にエンコードされたデータごとにファイルからそのバイト数を読み取ります。

>>> import struct
>>> f = open('test', 'wb')
>>> entry1 = 'this is a test\n'.encode('utf-16')
>>> struct.pack('!h', len(entry1)))
>>> f.write(entry1)
>>> entry2 = 'another test\n'.encode('utf-8')
>>> f.write(struct.pack('!h', len(entry2)))
>>> f.write(entry2)
>>> f.close()

structモジュールを使用して、固定長データを書き込みました。ファイルもバイナリとして記述していることに注意してください。

読む:

>>> f = open('test', 'rb')
>>> fieldsize = struct.calcsize('!h')
>>> length = struct.unpack('!h', f.read(fieldsize))[0]
>>> print f.read(length).decode('utf-16')
this is a test

>>> length = struct.unpack('!h', f.read(fieldsize))[0]
>>> print f.read(length).decode('utf-8')
another test

>>>

再び、ファイルはバイナリ モードで開かれます。

実際のアプリケーションでは、おそらくエントリごとにエンコーディング情報も含める必要があります。

于 2012-06-20T08:48:58.403 に答える
1

コードの作業バージョン。基本的に改行をエンコードせず、 readline() メソッドを呼び出すときにそれらを削除します。

f = open('test','w')
f.write('this is a test'.encode('utf-16'))
f.write("\n")
f.write('another test'.encode('utf-8'))
f.write("\n")
f.close()

f = open("test")
print f.readline().strip("\n").decode('utf-16')
print f.readline().strip("\n").decode('utf-8')
于 2012-06-20T09:29:09.940 に答える
0

同じファイルで 2 つの異なるエンコーディングを使用することはよくない考えであることが一般に認められています。要素にエンコーディングを指定できる構造化ファイル(XML、JSONなど)がある場合にのみ、役立つと思います。

<entries>
    <entry encoding="utf-16">
        <text>私&lt;/text>
        <meaning>I, myself</meaning>
    </entry>
    <entry encoding="utf-8">
        <text>あなた&lt;/text>
        <meaning>you, yourself</meaning>
    </entry>
</entries>

擬似コード:

for entry in entries:
    text += entry.text.decode(entry.encoding)

また、システムがリトル エンディアンであり、readline が utf-16 文字の途中で改行しているため、例が失敗しています。これにより、最初の行の最後の \x00 が失われ、最後の行の先頭に utf-16 行の \x00 が追加されます。ここに簡単な修正があります:

f = open("test")
print (f.readline()+'\x00').decode('utf-16')  # it leads to UnicodeDecodeError
print f.readline()[1:].decode('utf-8')   # it works fine
于 2012-06-20T07:35:53.553 に答える
0

行の先頭にいくつかのマーカーを使用できませんでしたか?

>>> f = open('test','w')
f.write('16 - this is a test\n'.encode('utf-16'))
f.write('8 - another test\n'.encode('utf-8'))
f.close()
>>> f = open('test')
>>> for line in f:
    if line.startswith('8 - '):
        print line.replace('8 - ', '').decode('utf-8')
    elif line.startswith('16'):
        print line.replace('16 - ', '').decode('utf-16')
于 2012-06-20T07:34:19.030 に答える