【问题标题】:Python regex £ signPython 正则表达式 £ 符号
【发布时间】:2015-05-31 05:48:33
【问题描述】:

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

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

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

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

这似乎正确地找到了井号,但是 £ 不是用任何东西替换它们,而是转换为这个符号:Â

有人知道发生了什么吗?

【问题讨论】:

  • 在处理特殊字符时,您应该非常注意编码。确保您知道您打开的文件的编码、您编写的文件和您自己的代码。如果您使用 Python 2.x,请相应地标记您的问题,因为两个版本的编码处理不同。
  • codecs.open而不是open,然后就做string.replace(u'£', ''),这里不需要regex。
  • @alessadro:Python 源代码编码与问题无关

标签: python regex unicode utf-8


【解决方案1】:

总结:

在 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 字符串与字节字符串混合在一起。对具有不同编码的字符进行替换是没有意义的。这实质上是替换字节而不是字符。

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

【讨论】:

  • 这是错误的,或者充其量是误导。 unichr 的存在表明 OP 使用 Python 2。read() 在这种情况下返回一个字节串(一个字节序列)——图片中任何地方都没有 unicode 类型(你可以写 anything 在到文件中,read() 无论如何都可以使用)。如果您在打印两个 bytes 时看到 £ print b'\xc2\xa3' 表示您的终端/控制台使用 cp1252 或类似的字符编码(我会看到 £ 因为我的终端使用 utf-8 字符编码)。 The real issue is that OP mixes unicode and bytes that exposes the bug in re module.
  • @J.F.Sebastian 我认为我的回答对于遍历 OP 的代码和错误很有用。它确实有几个错误,我相信我已经纠正了。您的帖子简洁明了,展示了对 Python 中 unicode 的更好理解。道具。
  • 它更好,但它仍然具有误导性。字节串中的所有字节都只是字节。对于其中一些是否在 ascii 范围内的问题无关紧要 - 您的困惑来自 Python 的 repr(bytestring) 将一些字节(来自 graph 类)显示为字符,例如,b'\x22\x20\x22' 通常显示为 @987654355 @ -- 注意:文字(Python 源代码中的常量)是不同的,但字节串是相同的——它们由相同的字节序列组成:34、32、34(在 Python 3 中索引 a bytes 对象返回一个 Python int: b'a'[0] == 97
【解决方案2】:

问题在于您混合了 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)

【讨论】:

【解决方案3】:

这是 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()

【讨论】:

    猜你喜欢
    • 2016-09-12
    • 2013-02-14
    • 2013-11-22
    • 2022-12-04
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多