Python:将非 ASCII 字符保存到文件中

3
我正在尝试编写一个函数,它可以在命令提示符和文件中打印内容。以下代码会出现编码/解码错误:
import os

def pas(stringToProcess): #printAndSave
  print stringToProcess 
  try: f = open('file', 'a')
  except: f = open('file', 'wb')
  print  >> f, stringToProcess
  f.close()

all = {u'title': u'Pi\xf1ata', u'albumname': u'New Clear War {EP}', u'artistname': u'Montgomery'}

pas(all['title'])

我得到了以下输出:
Piñata
Traceback (most recent call last):
  File "new.py", line 17, in <module>
     pas(all['title'])
  File "new.py", line 11, in pas
    print  >> f, stringToProcess
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf1' in position 2: ordinal not in range(128)

我尝试了所有我能想到的encode()/decode()组合,但都没有成功。如何解决这个错误?

1
为什么在追加时以文本模式打开文件,但如果抛出异常则以二进制模式打开?虽然这里并不重要,因为您没有写入换行符,以追加模式打开文件将起作用,或者以“'wb'”模式打开文件的失败原因与以追加模式打开文件的失败原因相同。 - Martijn Pieters
1
而且 all['title'].encode('utf8') 也可以正常工作。你尝试了什么? - Martijn Pieters
1
我认为他可能正在尝试将内容追加到一个已存在的文件中,否则就创建一个新文件。 - Burhan Khalid
我尝试使用errors ='replace'和errors ='ignore'等各种编解码器,但是我认为我在对已经编码的字符串进行编码时遇到了问题,因为我之前也遇到过这些问题。一旦我除去了除函数中的一个之外的所有编码/解码痕迹,它就可以正常工作。Burhan Khalid正确。 - stretch
3个回答

3

正如有人评论的那样,当你写字符串时,你可能只需要指定使用哪种编解码器。例如,对于我来说,这个方法起作用:

def pas(s):
    print(s)
    with open("file", "at") as f:
        f.write("%s\n" % s.encode("utf-8"))

pas(u'Pi\xf1ata')
pas(u'Pi\xf1ata')

可以看到,我特别以追加/文本模式打开文件。如果文件不存在,则会创建该文件。我还使用with而不是您的try-except方法。这仅仅是我喜欢的风格。

正如Bhargav所说,您也可以设置默认编码方式。这完全取决于您在程序中需要多少控制,两种方式都可以。


1
一个更简单的方法是使用'codecs.open(),因为任何写入/读取的数据的编码/解码都会自动完成。 - martineau
@martineau 我其实不知道这个!它在文件第一次创建时默认为UTF-8吗?谢谢。 - csl
文档没有提到默认编码,虽然该参数是可选的...所以我会假设如果未指定编码,则它不会为您执行任何编码(尽管这将使其与常规的 open() 相同)。 - martineau

3

使用sys.setdefaultencoding('utf8')可以防止出现错误。

就是这样。

import os,sys
reload(sys)  
sys.setdefaultencoding('utf8')
def pas(stringToProcess): #printAndSave
  print stringToProcess 
  try: f = open('file', 'a')
  except: f = open('file', 'wb')
  print  >> f, stringToProcess
  f.close()

all = {u'title': u'Pi\xf1ata', u'albumname': u'New Clear War {EP}', u'artistname': u'Montgomery'}

pas(all['title'])

这将打印


Piñata

1

我刚刚尝试了这个方法,它有效,我阅读了一个有趣的问题

编码总是有点棘手:

def pas(stringToProcess): #printAndSave
    strtp = stringToProcess.encode('utf-8')
    print stringToProcess
    try: f = open('file.txt', 'a')
    except: f = open('file.txt', 'wb')
    f.write(strtp)
    f.close()

all = {u'title': u'Pi\xf1ata', u'albumname': u'New Clear War {EP}', u'artistname': u'Montgomery'}

pas(all['title'])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接