如何使用正则表达式可移植地解析(Unicode)度数符号?

Posted

技术标签:

【中文标题】如何使用正则表达式可移植地解析(Unicode)度数符号?【英文标题】:How to portably parse the (Unicode) degree symbol with regular expressions? 【发布时间】:2012-02-15 16:03:21 【问题描述】:

我正在为 Ubuntu 上的 sensors 实用程序的输出编写一个简单的正则表达式解析器。这是我正在解析的一行文本的示例:

temp1:        +31.0°C  (crit = +107.0°C)

这是我用来匹配它的正则表达式(在 Python 中):

temp_re = re.compile(r'(temp1:)\s+(\+|-)(\d+\.\d+)\W\WC\s+' 
                     r'\(crit\s+=\s+(\+|-)(\d+\.\d+)\W\WC\).*')

此代码按预期工作,并与我上面给出的示例文本相匹配。我真正感兴趣的唯一位是数字,所以这一位:

(\+|-)(\d+\.\d+)\W\WC

以匹配+- 符号开始,以匹配°C 结束。

我的问题是,为什么需要两个 \W(非字母数字)字符来匹配 ° 而不是一个?在 Unicode 的表示方式与我的不同的系统上,代码会中断吗?如果是这样,我怎样才能让它便携?

【问题讨论】:

带有re.UNICODE 标志,RE 与\W\WC\WC 都不匹配。或者,我误会你了吗? 还有“”,它是一个单个字符,表示摄氏度。非常感谢 Unicode 联盟! 【参考方案1】:

可能的便携式解决方案:

将输入数据转换为unicode,并在正则表达式中使用re.UNICODE标志。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re


data = u'temp1:        +31.0°C  (crit = +107.0°C)'
temp_re = re.compile(ur'(temp1:)\s+(\+|-)(\d+\.\d+)°C\s+' 
                     ur'\(crit\s+=\s+(\+|-)(\d+\.\d+)°C\).*', flags=re.UNICODE)

print temp_re.findall(data)

输出

[(u'temp1:', u'+', u'31.0', u'+', u'107.0')]

编辑

@netvope 已经在 cmets 中指出了这一点。

更新

J.F. Sebastiancmets 关于输入编码的说明:

check_output() 返回的二进制数据有时可以是文本(在这种情况下应该具有已知的字符编码,您可以将其转换为 Unicode)。无论如何 ord(u'°') == 176 所以它不能使用 ASCII 编码进行编码。

因此,要将输入数据解码为unicode,基本上*您应该使用来自系统语言环境的编码,使用locale.getpreferredencoding(),例如:

data = subprocess.check_output(...).decode(locale.getpreferredencoding())

正确编码的数据:

在这种情况下,如果没有 re.UNICODE,您将获得相同的输出。


为什么?因为在俄语 Win7 上,cp1251preferredencoding,如果我们有例如 script.py 解码它的输出到 utf-8

#!/usr/bin/env python
# -*- coding: utf8 -*-

print u'temp1: +31.0°C  (crit = +107.0°C)'.encode('utf-8')

我们需要解析它的输出:

subprocess.check_output(['python', 
                         'script.py']).decode(locale.getpreferredencoding())

会产生错误的结果:'В°' 而不是°

因此,在某些情况下,您需要了解输入数据的编码。

【讨论】:

当然,但是为这类事情提供一个完整的工作示例总是一个好主意。即使有完整的设施,对于许多程序员来说,正确处理 Unicode 也很困难:( +1:用于“将输入数据转换为 unicode”。顺便说一句,在这种情况下,如果没有 re.UNICODE,您将获得相同的输出。 谢谢。我玩过它。在“真实”代码中,数据实际上来自对subprocess.check_output 的调用的输出,该调用将其数据返回为 ASCII,而不是 Unicode,因此这在此处不太适用。也许更明智的做法是迁移到“一切”都是 Unicode 的 Python3?嗯。 @snim2: check_output() 返回二进制数据,有时可以是文本(that should have a known character encoding in this case,您可以将其转换为Unicode)。无论如何ord(u'°') == 176 所以它不能使用ASCII 编码进行编码。 Python 3 无法帮助您,因为 check_output 可以返回没有意义的文本数据,例如二进制图像数据(您无法将其转换为 Unicode;没有关联的字符编码)。 @reclosedev:你的意思可能是locale.getpreferredencoding()。它完全独立于用于脚本的源编码。

以上是关于如何使用正则表达式可移植地解析(Unicode)度数符号?的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式和 unicode

使用 CountVectorizer 的无空格 unicode 句子的正则表达式

如何在 perl 正则表达式替换命令中使用 unicode 字符?

如何规范地解析模块名称

使用 wmemset() 的代码的可移植性如何?

正则表达式修饰符 - 可选标志