Python:2.6与3.1字符串匹配不一致的问题

0 投票
4 回答
523 浏览
提问于 2025-04-16 05:03

我用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 个回答

1

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版本了。

3

你在使用 print 输出 i[1:-3],但是在循环中却比较 i[1:-2]


非常重要的问题

你为什么要写代码来解析 XML 呢?其实 lxml 这个库可以帮你完成所有这些工作!单元测试的目的是为了测试你的代码,而不是确保你使用的库能正常工作!

1

拉塞尔·博罗格罗夫说得对。

在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')))

谢谢大家的回复!我很感激你们的帮助。

撰写回答