用Python从文件中读取字符


102

在文本文件中,有一个字符串“我不喜欢这样”。

但是,当我将其读取为字符串时,它变成“我不这样\ xe2 \ x80 \ x98t”。我了解\ u2018是“'”的Unicode表示形式。我用

f1 = open (file1, "r")
text = f1.read()

命令来做阅读。

现在,是否可以以这样的方式读取字符串,即当将其读入字符串时,它是“我不喜欢这样”而不是“我不喜欢这样”吗?

第二编辑:我已经看到有人使用映射来解决此问题,但实际上,没有内置的转换可以将这种ANSI转换为unicode(反之亦然)吗?


一些评论:我见过有人使用映射来解决此问题,但实际上,没有内置的转换可以将这种ANSI转换为unicode(反之亦然)吗?谢谢!
重力

没有,因为有成千上万的Unicode代码点。您将如何决定应将哪个映射到哪些ASCII字符?
约翰·米利金

2
顺便说一句,您的文本文件已损坏!U + 2018是“左单引号”,而不是撇号(U + 0027最常见)。

约翰,您的评论至少在一般意义上是错误的。iconv lib可用于将unicode字符音译为ascii(甚至取决于语言环境。$ python -c'print u“ \ u2018” .encode(“ utf-8”)'| iconv -t'ascii // translit'| xxd 0000000:270a

事实是,您需要将UNICODE转换为ASCII(而不是相反)。
哈森

Answers:


157

参考:http : //docs.python.org/howto/unicode

因此,从文件读取Unicode很简单:

import codecs
with codecs.open('unicode.rst', encoding='utf-8') as f:
    for line in f:
        print repr(line)

也可以在更新模式下打开文件,从而允许读取和写入:

with codecs.open('test', encoding='utf-8', mode='w+') as f:
    f.write(u'\u4500 blah blah blah\n')
    f.seek(0)
    print repr(f.readline()[:1])

编辑:我假设您的预期目标是能够将文件正确读取为Python中的字符串。如果您尝试从Unicode转换为ASCII字符串,那么实际上没有直接的方法,因为Unicode字符不一定存在于ASCII中。

如果您尝试转换为ASCII字符串,请尝试以下操作之一:

  1. 如果您只想处理一些特殊情况(例如此特定示例),请使用ASCII等价的方式替换特定的unicode字符。

  2. 使用unicodedata模块normalize()string.encode()方法将最大程度地转换为下一个最接近的ASCII等效词(参阅https://web.archive.org/web/20090228203858/http://techxplorer.com/2006/07/18/converting- unicode-to-ascii-using-python):

    >>> teststr
    u'I don\xe2\x80\x98t like this'
    >>> unicodedata.normalize('NFKD', teststr).encode('ascii', 'ignore')
    'I donat like this'

3
codecs模块无法正确处理通用换行模式。使用io.open()而不是在Python的2.7+(它是内置open()在Python 3中)。
jfs 2015年

15

有几点要考虑。

\ u2018字符只能作为Python中unicode字符串表示形式的一部分出现,例如,如果您编写:

>>> text = u'‘'
>>> print repr(text)
u'\u2018'

现在,如果您只是想简单地打印unicode字符串,只需使用unicode的encode方法:

>>> text = u'I don\u2018t like this'
>>> print text.encode('utf-8')
I dont like this

为了确保将任何文件中的每一行都读为unicode,最好使用codecs.open函数而不是just open,它允许您指定文件的编码:

>>> import codecs
>>> f1 = codecs.open(file1, "r", "utf-8")
>>> text = f1.read()
>>> print type(text)
<type 'unicode'>
>>> print text.encode('utf-8')
I dont like this

6

但这确实是“我不喜欢这样”而不是“我不喜欢这样”。字符u'\ u2018'与“'”是完全不同的字符(并且在视觉上应更对应于“`”)。

如果您尝试将编码的unicode转换为纯ASCII,则可以保留要转换为ASCII的unicode标点的映射。

punctuation = {
  u'\u2018': "'",
  u'\u2019': "'",
}
for src, dest in punctuation.iteritems():
  text = text.replace(src, dest)

unicode中有很多标点符号,但是,我想您只能指望其中的几个实际被创建您正在阅读的文档的应用程序所实际使用。


1
实际上,如果使字典将Unicode常规映射到Unicode常规({0x2018:0x27,0x2019:0x27}),您可以将整个dict传递给text.translate()一次完成所有替换。
Thomas Wouters

5

也可以使用python 3 read方法读取编码的文本文件:

f = open (file.txt, 'r', encoding='utf-8')
text = f.read()
f.close()

使用此变体,无需导入任何其他库


3

撇开您的文本文件已损坏的事实(U + 2018是左引号,而不是撇号):iconv可用于将unicode字符音译为ascii。

您必须在Google上搜索“ iconvcodec”,因为该模块似乎不再受支持,而且我也找不到它的规范主页。

>>> import iconvcodec
>>> from locale import setlocale, LC_ALL
>>> setlocale(LC_ALL, '')
>>> u'\u2018'.encode('ascii//translit')
"'"

或者,您可以使用iconv命令行实用程序来清理文件:

$ xxd foo
0000000: e280 980a                                ....
$ iconv -t 'ascii//translit' foo | xxd
0000000: 270a                                     '.

2

您可能会以某种方式拥有带有Unicode转义字符的非Unicode字符串,例如:

>>> print repr(text)
'I don\\u2018t like this'

这实际上发生在我之前。您可以使用unicode_escape编解码器将字符串解码为unicode,然后将其编码为所需的任何格式:

>>> uni = text.decode('unicode_escape')
>>> print type(uni)
<type 'unicode'>
>>> print uni.encode('utf-8')
I dont like this

1

这是Python的方法,向您显示unicode编码的字符串。但我认为您应该能够在屏幕上打印字符串或将其写入新文件而不会出现任何问题。

>>> test = u"I don\u2018t like this"
>>> test
u'I don\u2018t like this'
>>> print test
I dont like this

1

实际上,U + 2018是特殊字符'的Unicode表示。如果需要,可以使用以下代码将该字符的实例转换为U + 0027:

text = text.replace (u"\u2018", "'")

另外,您用什么来写文件?f1.read()应该返回一个看起来像这样的字符串:

'I don\xe2\x80\x98t like this'

如果返回字符串,则表示文件编写不正确:

'I don\u2018t like this'

抱歉! 正如你所说,它返回“我不\ XE2 \ X80 \ x98t这样”
引力

您看到的“我不喜欢\ xe2 \ x80 \ x98t”是Python称之为str的东西。它似乎是u'我不喜欢这样'的utf-8编码,它是Python中的unicode实例。尝试在前者上调用.decode('utf-8')或在后者上调用.encode('utf-8')。
罗根

@hop:哎呀,忘记了ord()返回十进制而不是十六进制。谢谢你的帮助。
约翰·米利金
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.