Python中的版本号比较
我想写一个类似于 cmp
的函数,用来比较两个版本号,并根据比较的结果返回 -1
、0
或 1
。
- 如果版本 A 比版本 B 旧,就返回
-1
- 如果版本 A 和版本 B 是一样的,就返回
0
- 如果版本 A 比版本 B 新,就返回
1
每个小部分都应该被看作一个数字,所以 1.10 是大于 1.1 的。
期望的函数输出是
mycmp('1.0', '1') == 0
mycmp('1.0.0', '1') == 0
mycmp('1', '1.0.0.1') == -1
mycmp('12.10', '11.0.0.0.0') == 1
...
这是我实现的代码,欢迎改进:
def mycmp(version1, version2):
parts1 = [int(x) for x in version1.split('.')]
parts2 = [int(x) for x in version2.split('.')]
# fill up the shorter version with zeros ...
lendiff = len(parts1) - len(parts2)
if lendiff > 0:
parts2.extend([0] * lendiff)
elif lendiff < 0:
parts1.extend([0] * (-lendiff))
for i, p in enumerate(parts1):
ret = cmp(p, parts2[i])
if ret: return ret
return 0
顺便说一下,我使用的是 Python 2.4.5(在我工作地方安装的...)。
这里有一个小的“测试套件”,你可以用来测试
assert mycmp('1', '2') == -1
assert mycmp('2', '1') == 1
assert mycmp('1', '1') == 0
assert mycmp('1.0', '1') == 0
assert mycmp('1', '1.000') == 0
assert mycmp('12.01', '12.1') == 0
assert mycmp('13.0.1', '13.00.02') == -1
assert mycmp('1.1.1.1', '1.1.1.1') == 0
assert mycmp('1.1.1.2', '1.1.1.1') == 1
assert mycmp('1.1.3', '1.1.3.000') == 0
assert mycmp('3.1.1.0', '3.1.2.10') == -1
assert mycmp('1.1', '1.10') == -1
17 个回答
31
在这种情况下,重用算不算优雅呢? :)
# pkg_resources is in setuptools
# See http://peak.telecommunity.com/DevCenter/PkgResources#parsing-utilities
def mycmp(a, b):
from pkg_resources import parse_version as V
return cmp(V(a),V(b))
293
你可以试试用Python的 distutils.version.StrictVersion
来处理版本号。
>>> from distutils.version import StrictVersion
>>> StrictVersion('10.4.10') > StrictVersion('10.4.9')
True
对于你的 cmp
函数来说:
>>> cmp = lambda x, y: StrictVersion(x).__cmp__(y)
>>> cmp("10.4.10", "10.4.11")
-1
如果你想比较更复杂的版本号,distutils.version.LooseVersion
会更有用,不过要确保你比较的是同类型的版本号。
>>> from distutils.version import LooseVersion, StrictVersion
>>> LooseVersion('1.4c3') > LooseVersion('1.3')
True
>>> LooseVersion('1.4c3') > StrictVersion('1.3') # different types
False
不过,LooseVersion
并不是最聪明的工具,容易被欺骗:
>>> LooseVersion('1.4') > LooseVersion('1.4-rc1')
False
要想用好这个工具,你需要跳出标准库,使用 setuptools 提供的解析工具 parse_version
。
>>> from pkg_resources import parse_version
>>> parse_version('1.4') > parse_version('1.4-rc2')
True
所以,根据你的具体需求,你需要决定是使用内置的 distutils
工具就够了,还是需要添加 setuptools
作为依赖。
41
去掉字符串中不重要的部分(比如末尾的零和点),然后再比较数字列表。
import re
def mycmp(version1, version2):
def normalize(v):
return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
return cmp(normalize(version1), normalize(version2))
这和Pär Wieslander的方法差不多,但稍微简洁一些:
这里有一些测试,感谢“如何在Bash中比较两个以点分隔的版本字符串?”:
assert mycmp("1", "1") == 0
assert mycmp("2.1", "2.2") < 0
assert mycmp("3.0.4.10", "3.0.4.2") > 0
assert mycmp("4.08", "4.08.01") < 0
assert mycmp("3.2.1.9.8144", "3.2") > 0
assert mycmp("3.2", "3.2.1.9.8144") < 0
assert mycmp("1.2", "2.1") < 0
assert mycmp("2.1", "1.2") > 0
assert mycmp("5.6.7", "5.6.7") == 0
assert mycmp("1.01.1", "1.1.1") == 0
assert mycmp("1.1.1", "1.01.1") == 0
assert mycmp("1", "1.0") == 0
assert mycmp("1.0", "1") == 0
assert mycmp("1.0", "1.0.1") < 0
assert mycmp("1.0.1", "1.0") > 0
assert mycmp("1.0.2.0", "1.0.2") == 0