递增尾随数字时字符串操作怪异

时间:2012-04-13 02:46:01

标签: python regex string

我收到了这段代码:

myString = 'blabla123_01_version6688_01_01Long_stringWithNumbers'
versionSplit = re.findall(r'-?\d+|[a-zA-Z!@#$%^&*()_+.,<>{}]+|\W+?', myString)

for i in reversed(versionSplit):
    id = versionSplit.index(i)
    if i.isdigit():
        digit = '%0'+str(len(i))+'d'
        i = int(i) + 1
        i = digit % i
        versionSplit[id]=str(i)
        break

final = ''
myString = final.join(versionSplit)
print myString

假设只增加给定字符串的最后一位数字。但是如果运行该代码,您将看到如果字符串中的数字与最后一个数字相同,那么如果您继续运行该脚本,它将一个接一个地增加它。任何人都可以帮我找出原因吗?

提前感谢您的任何帮助

4 个答案:

答案 0 :(得分:8)

你有没有理由不做这样的事情:

prefix, version = re.match(r"(.*[^\d]+)([\d]+)$", myString).groups()
newstring = prefix + str(int(version)+1).rjust(len(version), '0')

注意:

  • 这实际上会“正确地”结转版本号:(“09” - &gt;“10”)和(“99” - &gt;“100”)
  • 此正则表达式假设在最后的最终版本子字符串之前至少有一个非数字字符。如果不匹配,则会抛出AttributeError。您可以重新构建它以引发更合适或特定的例外(例如,如果re.match(...)返回None;请参阅下面的评论以获取更多信息)。

相应调整。

答案 1 :(得分:2)

问题是在第5行使用list.index()函数。这会从列表中返回第一次出现的值,从左到右,但是代码迭代颠倒的列表(从右到左)。有很多方法可以解决这个问题,但这里有一个对现有代码进行最少更改的方法:反向迭代索引(避免反转列表)。

for idx in range(len(versionSplit)-1, -1, -1):
    i = versionSplit[idx]
    if chunk.isdigit():
        digit = '%0'+str(len(i))+'d'
        i = int(i) + 1
        i = digit % i
        versionSplit[idx]=str(i)
        break

答案 2 :(得分:1)

myString = 'blabla123_01_version6688_01_01veryLong_stringWithNumbers01'
versionSplit = re.findall(r'-?\d+|[^\-\d]+', myString)

for i in xrange(len(versionSplit) - 1, -1, -1):
    s = versionSplit[i]
    if s.isdigit():
        n = int(s) + 1
        versionSplit[i] = "%0*d" % (len(s), n)
        break

myString = ''.join(versionSplit)
print myString

注意:

  • 使用.index()方法尝试查找字符串是很愚蠢的。只需使用递减索引来尝试versionSplit的每个部分。这就是你的问题所在,正如上面@David Robinson所评论的那样。

  • 不要将id用作变量名;你掩盖了内置函数id()

  • 此代码在格式模板中使用*,该模板将接受整数并设置宽度。

  • 我简化了模式:要么匹配一个数字(带有可选的前导减号),要么就是匹配非数字。

  • 我对此进行了测试,似乎有效。

答案 3 :(得分:1)

首先,三个注释:

  1. id是一个保留的python字;
  2. 对于加入,使用文字空字符串''.join()更加pythonic成语
  3. reversed()返回迭代器,而不是列表。这就是我使用list(reversed())的原因,以便稍后rev.index(i)
  4. 更正后的代码:

    import re
    
    myString = 'blabla123_01_version6688_01_01veryLong_stringWithNumbers01'
    print myString
    versionSplit = re.findall(r'-?\d+|[a-zA-Z!@#$%^&*()_+.,<>{}]+|\W+?', myString)
    
    rev = list(reversed(versionSplit))  # create a reversed list to work with from now on
    
    for i in rev:
        idd = rev.index(i)
        if i.isdigit():
            digit = '%0'+str(len(i))+'d'
            i = int(i) + 1
            i = digit % i
            rev[idd]=str(i)
            break
    
    myString = ''.join(reversed(rev))  # reverse again only just before joining
    print myString