Python:2.6与3.1字符串匹配不一致的问题
我用Python 3.1.2写了我的模块,但现在我需要让它在2.6.4上运行。
我不打算把所有代码都发上来,因为那样可能会让人困惑。
简单说一下情况: 我正在写一个XML解析器(这是我第一次接触XML),它可以从XML文件中创建对象。因为对象很多,所以我写了一个“单元测试”,手动扫描XML,试图找到匹配的对象。如果找不到匹配的对象,它会打印出来。
我打开XML文件,用一个简单的'for'循环逐行读取文件。如果我找到一个符合“应用程序”正则表达式的节点(XML有不同的“应用程序”节点),我就把它作为键添加到我的字典d中。然后我对标题执行lxml.etree.xpath()查询,并把结果存储为值。 在遍历完整个文件后,我会遍历我的字典d,尝试将键与值匹配(我需要使用“应用程序”类中的get()方法)。每当发现不匹配时,我就打印出键和标题。 在Python 3.1.2中,字典里的所有项都匹配,所以什么都没打印出来。但在2.6.4中,所有的值(大约600个)都被打印出来。我搞不懂为什么我的字符串比较不成功。
不多说,这里是相关的代码:
for i in d:
if i[1:-2] != d[i].get('id'):
print('X%sX Y%sY' % (i[1:-3], d[i].get('id')))
我对字符串进行了切片,因为字符串的格式不同。比如键是"9626-2008olympics_Prod-SH",而值是9626-2008olympics_Prod-SH,所以我得去掉引号和换行符。我还在打印语句中加了X和Y,以确保没有空格问题。 这是一个输出示例:
X9626-2008olympics_Prod-SHX Y9626-2008olympics_Prod-SHY
记得忽略X和Y。这两个字符串是完全相同的。我不明白为什么Python2无法匹配它们。
编辑: 问题似乎出在我的切片方式上。 在Python3中,
if i[1:-2] != d[i].get('id'):
这个比较是没问题的。
在Python2中,
if i[1:-3] != d[i].get('id'):
我需要把偏移量改为1。
为什么字符串需要不同的偏移量呢?我能想到的唯一可能是Python2把换行符当作两个字符(即'\' + 'n')。
编辑2: 更新了请求的repr()信息。
我添加了一小段代码来生成上面“2008olympics”示例的repr()信息。我没有进行任何切片。看起来这可能不是一个unicode问题。现在出现了一个"\r"字符。 Python2:
'"9626-2008olympics_Prod-SH"\r\n' '9626-2008olympics_Prod-SH'
Python3:
'"9626-2008olympics_Prod-SH"\n' '9626-2008olympics_Prod-SH'
看起来这个文件是在Windows上创建或修改的。在Python2中有没有办法自动去掉'\r'?
4 个回答
repr() 和 %r 格式是你的好帮手 ... 它们能让你看到(对于基本类型,比如字符串/Unicode/字节)你到底得到了什么,包括类型。
不要这样做:
print('X%sX Y%sY' % (i[1:-3], d[i].get('id')))
要这样做:
print('%r %r' % (i, d[i].get('id')))
注意不要省略 [1:-3]
,这样你可以在切片之前看到 i
里面有什么。
根据评论的更新 “你说得对,比较了错误的切片。不过,一旦我改了它,python2.6可以工作,但python3现在有问题(也就是说,它不匹配任何对象)”:
你是怎么打开文件的(请分别给出Python 2和3的答案)。你是在Windows上运行吗?你试过获取我建议的repr()吗?
根据OP最终提供的实际输入的更新:
如果你的输入文件是在Windows上创建的(行是用 "\r\n"
分隔的),你可以通过使用通用换行符选项来便捷地读取Windows和*x文本文件 ... 在Python2中使用 open('datafile.txt', 'rU')
-- 详细信息请查看这里。在Python3中,通用换行符模式是默认的。请注意,Python3文档说你也可以在Python3中使用 'rU'
;这样你就不需要测试你使用的是哪个Python版本了。
你在使用 print
输出 i[1:-3]
,但是在循环中却比较 i[1:-2]
。
非常重要的问题
你为什么要写代码来解析 XML 呢?其实 lxml
这个库可以帮你完成所有这些工作!单元测试的目的是为了测试你的代码,而不是确保你使用的库能正常工作!
拉塞尔·博罗格罗夫说得对。
在Python 3中,默认使用的是unicode编码,换行符被正确地当作一个字符来处理。这就是为什么我在3中使用[1:-2]这个切片可以正常工作的原因,因为我需要去掉三个字符:", "和\n。
而在Python 2中,换行符被当作两个字符来处理,这样我就得去掉四个字符,使用[1:-3]。
我刚刚添加了一个手动检查来判断Python的主要版本。
这是修正后的代码:
for i in d:
# The keys in D contain quotes and a newline which need
# to be removed. In v3, newline = 1 char and in v2,
# newline = 2 char.
if sys.version_info[0] < 3:
if i[1:-3] != d[i].get('id'):
print('%s %s' % (i[1:-3], d[i].get('id')))
else:
if i[1:-2] != d[i].get('id'):
print('%s %s' % (i[1:-2], d[i].get('id')))
谢谢大家的回复!我很感激你们的帮助。