Python正则表达式£符号

时间:2015-03-27 00:56:08

标签: python regex unicode utf-8

我正在阅读一个包含井号(£)的文本文件:

f = open(file, 'r')
string = f.read()
f.close()

除了一些其他的正则表达式操作,我想删除这些井号,并将该字符串写入新文件。我最接近完成这项工作的是以下代码:

n = re.compile(unichr(163))
string = n.sub('', string)

这似乎正确地找到了英镑符号,但是£不会替换为任何符号,而是转换为此符号:Â

任何人都知道发生了什么事?

3 个答案:

答案 0 :(得分:3)

要点:

  

在utf8中,£映射到原始字节\xc2\xa3re模块允许在unicode和字节编码的字符串之间进行字符串替换,这是一个错误。

我认为J.F. Sebastian的answer更加娴熟,但这是一个演练。

详细说明:

调用read()返回字节串。

为了说明,我们创建以下文件durp

echo -n "£" > durp

下一个命令以十六进制格式获取文件的内容:

$ cat durp | xxd  | cut -d " " -f 2
c2a3

注意:访问此url会在多个编码中显示£

这些是构成£的原始字节。 python在读取时对文件做了什么?

$ python
> f = open("durp")
> f.read()
'\xc2\xa3'

它不知道编码是什么,所以它表示转义的十六进制形式的字节。

让我们导入您的代码:

> import re
> r = re.compile(u'£')
> u'£'
u'\xa3'

最后一行只是为了看看我们正在制作一个模式。这是错误的来源。

现在我们对文件内容执行替换:

> r.sub('', '\xc2\xa3')
'\xc2'

这是可以想象但错误的。我们在'\xa3'中将''替换为'\xc2\xa3'并获得了'\xc2'。这是re中的错误,因为unicode字符串与bytestrings混合在一起。执行具有不同编码的字符的子集是没有意义的。这基本上是替换字节而不是字符。

J.F。 Sebastian的answer解释了您的终端如何将'\xc2'解释为Â

答案 1 :(得分:2)

Python 2中re模块中的一个错误是允许混合unicode模式和输入字节串:它使用latin-1编码静默编码模式,导致错误的结果。 Python 3在这里正确地引发了TypeError

>>> u'\N{POUND SIGN}'.encode('latin-1')
'\xa3'
>>> u'\N{POUND SIGN}'.encode('utf-8')                                                                     
'\xc2\xa3'
>>> import re
>>> re.sub(u'\N{POUND SIGN}', '', u'\N{POUND SIGN}'.encode('utf-8'))                                      
'\xc2'
>>> print(re.sub(u'\N{POUND SIGN}', '', u'\N{POUND SIGN}'.encode('utf-8')).decode('cp1252'))              
Â
>>> print(re.sub(u'\N{POUND SIGN}', '', u'x\N{POUND SIGN}y'))
xy

解决方案是对模式和输入字符串使用Unicode:

import io

with io.open('file.txt', encoding='utf-8') as file:
     result = file.read().replace(u'\N{POUND SIGN}', '')

codecs模块无法正确处理通用换行符,而是使用io模块。 Python 3中的内置open()函数是io.open()

答案 2 :(得分:0)

问题是你要混合8位字符串和完整的Unicode字符串。 @cdosborn已经很好地描述了这是如何导致部分替换字符的。

在Python中> 2.x,有两种保存文本的方法:字符串和Unicode字符串。字符串可以包含纯ASCII,ANSI,Windows-1252,UTF-8,UTF-16中的文本编码。问题是必须知道如果你需要转换它,文本的编码是什么。手上的Unicode字符串完全是明确的,因为它们是使用已知编码从字符串显式转换的结果,使用Unicode转义码(u" \ u00A3"),或者像unichr这样的函数( )。

最佳做法是始终在输入代码时将字符串解码为Unicode。然后编码出路。这是Python 3.x和其他语言(如Java)的默认行为。

如果您正在处理文件,codecs模块提供了一种在以下方式将文本转换为Unicode字符串的好方法:

my_file = codecs.open("filename.txt", "r", "utf-8")
my_unicode_string = my_file.read()

显然,如果您的文件采用其他编码方式,请更改编码名称utf-8 - 请参阅编解码器名称:https://docs.python.org/2/library/codecs.html#standard-encodings

如果您正在处理来自其他地方的字符串(stdin,webforms),请使用以下方法进行转换:

my_unicode_string = "my €uro sign in utf-8".decode("utf-8")

再次,相应地更改utf-8参数

获得Unicode字符串后,您可以根据自己的意愿自由使用。要做一个简单的搜索并替换英镑符号,请执行以下操作:

my_unicode_string.replace(unichr(163), "")

为了使您的代码更易于阅读,您可以使用UTF-8对源代码进行编码并声明编码。这意味着您不必在转义序列或序数中隐藏Unicode字符。

完全放弃:

# -*- coding: utf-8 -*-
my_file = codecs.open("filename.txt", "r", "utf-8")
my_unicode_string = my_file.read()
replaced_unicode_string = my_unicode_string.replace("£", "")

现在,如果您想将replaced_unicode_string写入另一个文件:

my_output_file = codecs.open("another_filename.txt", "w", "utf-8")
my_output_file.write(replaced_unicode_string)