Python 版本号比较
我想编写一个类似 cmp
的函数,比较两个版本号并返回 -1
、0
或 1
> 基于它们的比较值。
- 如果版本 A 比版本 B 旧,则返回
-1
- 如果版本 A 和 B 相同,则返回
0
- 如果版本 A 比版本新,则返回
1
B
每个小节都应该被解释为一个数字,因此 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
I want to write a cmp
-like function that compares two version numbers and returns -1
, 0
, or 1
based on their compared values.
- Return
-1
if version A is older than version B - Return
0
if versions A and B are equivalent - Return
1
if version A is newer than version B
Each subsection is supposed to be interpreted as a number, therefore 1.10 > 1.1.
Desired function outputs are
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
...
And here is my implementation, open for improvement:
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
I'm using Python 2.4.5 btw. (installed at my working place ...).
Here's a small 'test suite' you can use
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
使用 Python 的
distutils.version.StrictVersion
怎么样?因此,对于您的
cmp
函数:如果您想比较更复杂的版本号,
distutils.version.LooseVersion
会更有用,但请确保仅比较相同的类型。LooseVersion
不是最智能的工具,很容易被欺骗:要在这个品种上取得成功,您需要走出标准库并使用 setuptools 的解析实用程序
parse_version
。因此,根据您的具体用例,您需要决定内置
distutils
工具是否足够,或者是否有必要将其添加为依赖项setuptools
。How about using Python's
distutils.version.StrictVersion
?So for your
cmp
function:If you want to compare version numbers that are more complex
distutils.version.LooseVersion
will be more useful, however be sure to only compare the same types.LooseVersion
isn't the most intelligent tool, and can easily be tricked:To have success with this breed, you'll need to step outside the standard library and use setuptools's parsing utility
parse_version
.So depending on your specific use-case, you'll need to decide whether the builtin
distutils
tools are enough, or if it's warranted to add as a dependencysetuptools
.删除字符串中不感兴趣的部分(尾随零和点),然后比较数字列表。
这与 Pär Wieslander 的方法相同,但更紧凑一些:
以下是一些测试,感谢“如何在 Bash 中比较点分隔版本格式的两个字符串?":
Remove the uninteresting part of the string (trailing zeroes and dots), and then compare the lists of numbers.
This is the same approach as Pär Wieslander, but a bit more compact:
Here are some tests, thanks to "How to compare two strings in dot separated version format in Bash?":
在这种情况下,重用是否被视为优雅? :)
Is reuse considered elegance in this instance? :)
无需迭代版本元组。列表和元组上的内置比较运算符已经完全按照您想要的方式工作。您只需要将版本列表零扩展到相应的长度。在 python 2.6 中,您可以使用 izip_longest 来填充序列。
对于较低版本,需要一些地图黑客技术。
No need to iterate over the version tuples. The built in comparison operator on lists and tuples already works exactly like you want it. You'll just need to zero extend the version lists to the corresponding length. With python 2.6 you can use izip_longest to pad the sequences.
With lower versions, some map hackery is required.
这比你的建议更紧凑一些。我不是用零填充较短的版本,而是在分割后从版本列表中删除尾随零。
This is a little more compact than your suggestion. Rather than filling the shorter version with zeros, I'm removing trailing zeros from the version lists after splitting.
使用正则表达式、
split
删除尾随的.0
和.00
并使用正确比较数组的cmp
函数:并且,当然,如果你不介意排长队,你可以将其转换为单行。
Remove trailing
.0
and.00
with regex,split
and usecmp
function which compares arrays correctly:And, of course, you can convert it to a one-liner if you don't mind the long lines.
它是单行(为了易读而分开)。不确定可读性...
It's a one liner (split for legability). Not sure about readable...
实现 php
version_compare
,“=”除外。因为它很暧昧。Implement for php
version_compare
, except "=". Because it's ambiguous.列表在 Python 中是可比较的,因此如果有人将表示数字的字符串转换为整数,则可以成功使用基本的 Python 比较。
我需要稍微扩展一下这种方法,因为我使用 Python3x,其中
cmp
函数不再存在。我必须使用(a > b) - (a < b)
来模拟cmp(a,b)
。而且,版本号根本不是那么干净,并且可以包含所有其他类型的字母数字字符。在某些情况下,函数无法区分顺序,因此会返回 False(请参阅第一个示例)。因此,即使这个问题很旧并且已经得到解答,我也会发布此内容,因为它可能会节省某人的生命几分钟。
Lists are comparable in Python, so if someone converts the strings representing the numbers into integers, the basic Python comparison can be used with success.
I needed to extend this approach a bit because I use Python3x where the
cmp
function does not exist any more. I had to emulatecmp(a,b)
with(a > b) - (a < b)
. And, version numbers are not that clean at all, and can contain all kind of other alphanumeric characters. There are cases when the function can't tell the order so it returnsFalse
(see the first example).So I'm posting this even if the question is old and answered already, because it may save a few minutes in someone's life.
如果您不想引入外部依赖项,这里是我为 Python 3.x 编写的尝试。
rc
、rel
(可能还可以添加c
)被视为“候选版本”,并将版本号分为两部分,如果缺少第二部分的值很高(999)。否则字母会产生分割并通过 36 进制代码作为子数字处理。In case you don't want to pull in an external dependency here is my attempt written for Python 3.x.
rc
,rel
(and possibly one could addc
) are regarded as "release candidate" and divide the version number into two parts and if missing the value of the second part is high (999). Else letters produce a split and are dealt as sub-numbers via base-36 code.最难阅读的解决方案,但仍然是一行字!并使用迭代器来提高速度。
这适用于 Python2.6 和 3.+ 顺便说一句,Python 2.5 及更早版本需要捕获 StopIteration。
The most difficult to read solution, but a one-liner nevertheless! and using iterators to be fast.
that is for Python2.6 and 3.+ btw, Python 2.5 and older need to catch the StopIteration.
我这样做是为了能够解析和比较 Debian 软件包版本字符串。请注意,它对字符验证并不严格。
这也可能有帮助:
I did this in order to be able to parse and compare the Debian package version string. Please notice that it is not strict with the character validation.
This might be helpful as well:
另一种解决方案:
也可以这样使用:
Another solution:
One can use like this too:
我在我的项目中使用这个:
i'm using this one on my project:
几年过去了,但这个问题仍然是最重要的。
这是我的版本排序功能。它将版本分为数字部分和非数字部分。数字按
int
进行比较,其余部分按str
进行比较(作为列表项的一部分)。您可以使用函数
key
作为带有比较运算符的自定义Version
类型。如果确实想使用cmp
你可以像下面的例子一样:https://stackoverflow.com /a/22490617/9935708测试套件通过。
Years later, but stil this question is on the top.
Here is my version sort function. It splits version into numbers and non-numbers sections. Numbers are compared as
int
rest asstr
(as parts of list items).You can use function
key
as kind of customVersion
type with compare operators. If out really want to usecmp
you can do it like in this example: https://stackoverflow.com/a/22490617/9935708Test suite passes.
我的首选解决方案:
用额外的零填充字符串,并且仅使用前四个是很容易理解的,
不需要任何正则表达式,并且 lambda 或多或少具有可读性。为了便于阅读,我使用两行,对我来说,优雅就是简短而简单。
My preferred solution:
Padding the string with extra zeroes and just using the four first is easy to understand,
doesn't require any regex and the lambda is more or less readable. I use two lines for readability, for me elegance is short and simple.
这是我的解决方案(用 C 编写,抱歉)。我希望你会发现它很有用
This is my solution (written in C, sorry). I hope you'll find it useful