如何比較版本號--Python實現


需求

在寫一個程序Django項目的setup程序(初始化環境,比如設置PIP源,安裝該項目依賴的各種模塊等操作)遇到一個系統當前模塊版本和項目所需版本的比較然后給出建議是忽略還是升級。我的要求是不僅僅比較版本號是否一致以及返回最大版本號,而且還要給出建議是升級(當前系統包的版本號小於項目需要的版本號)還是忽略(當前系統包的版本號大於等於項目需要的版本號)。下圖就是我們要去比較的東西。

解題分析

  • 版本號雖然是數字組成但是一個整體的版本號無法通過數字進行比較需要拆解逐位比較
  • 版本號有長度的區別我們可以稱作位,比如1.1.1這就是3位,我們這里的位說的是“.”分割的位數。 1.111.1也是三位。位數就是“.”的個數加1. 

算法一:補位算法

比如1.11.2和1.9比較,既然是逐位比較那就需要循環,兩個版本號位數不同如果按照最長的位數循環那短的哪一個肯定拋異常,那么我就可以通過補位來實現,怎么補呢?1.9 和 1.9.0 看到了么,這兩個版本號是相同的,為什么呢?有誰見過1位的版本號呢?都使用1.0而不會單純使用1,長度相同那剩下的就是循環比較。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys

def checkVersion(currentversion, expectedversion):
    """
    檢查版本號是否相同,當前版本小於期望版本則進行升級,大於等於則忽略。
    CODE有兩種,88和99 表示建議,88表示當前版本大於等於期待的版本忽略,99表示小於期待版本要進行升級。
    :param currentversion: 當前系統存在的版本號
    :param expectedversion: 期望的版本號
    :return: CODE, MAX_VERSION
    """

    MAX_VERSION = "0.0.0"
    CODE = 88

    # 如果兩者一樣就直接返回,用於加快處理速度。 這里不要用 is 要用 == 來比較內容是否一致。
    if expectedversion == currentversion:
        CODE = 88
        MAX_VERSION = expectedversion
        return CODE, MAX_VERSION

    # 切割成列表
    currentversionBITS = currentversion.split(".")
    expectedversionBITS = expectedversion.split(".")

    """
    為了避免版本號長度不同比如  1.0.8和1.2 我們把版本號要補全都變成相同長度,比如 1.2.0 這樣比較的時候循環次數相同
    """
    if len(currentversionBITS) >= len(expectedversionBITS):
        amount = len(currentversionBITS) - len(expectedversionBITS)
        for i in range(amount):
            expectedversionBITS.append("0")
    else:
        amount = len(expectedversionBITS) - len(currentversionBITS)
        for i in range(amount):
            currentversionBITS.append("0")

    """
    逐位比較版本大小,為什么這里采用currentversionBITS的長度來循環呢,其實講過上面的if語句后無論是currentversionBITS還是expectedversionBITS
    位數都相同,這里采用那個長度來控制循環都可以。
    """
    for i in range(len(currentversionBITS)):
        try:
            if int(currentversionBITS[i]) > int(expectedversionBITS[i]):
                CODE = 88
                MAX_VERSION = currentversion
                return CODE, MAX_VERSION
            elif int(currentversionBITS[i]) < int(expectedversionBITS[i]):
                CODE = 99
                MAX_VERSION = expectedversion
                return CODE, MAX_VERSION
            else:
                CODE = 88
                MAX_VERSION = expectedversion
        except IndexError as err:
            pass

    return CODE, MAX_VERSION

def main():
    print checkVersion("1.0", "1.1")  # 正確的返回 99 1.1
    print checkVersion("1.1.2", "1.1")  # 正確的返回 88 1.1.2
    print checkVersion("1.11.3", "1.11.24")  # 正確的返回 99 1.11.24
    print checkVersion("1.0.11.3", "1.0.11.2")  # 正確的返回 88 1.0.11.3

if __name__ == "__main__":
    try:
        main()
    finally:
        sys.exit()

執行結果

算法二:不補位按最小長度循環

不補位就要安裝最小位數長度循環,否則就會拋出異常,當然我們可以做異常處理,不過執行邏輯還是不要放在異常里因為異常會影響性能,再說明明這個異常可以避免干嘛還要讓它出現呢。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys

def checkVersionG2(currentversion, expectedversion):
    """
    檢查版本號是否相同,當前版本小於期望版本則進行升級,大於等於則忽略.本方法是基於第一種方法的改進,性能更好,代碼更少。
    CODE有兩種,88和99 表示建議,88表示當前版本大於等於期待的版本忽略,99表示小於期待版本要進行升級。
    :param currentversion: 當前系統存在的版本號
    :param expectedversion: 期望的版本號
    :return: CODE, MAX_VERSION
    """

    MAX_VERSION = "0.0.0"

    # 切割成列表
    currentversionBITS = currentversion.split(".")
    expectedversionBITS = expectedversion.split(".")

    """
    找出2個版本號位數最小的一個,注意這里就存在數據互換問題,經過這個if語句之后,你就完全不知道 minbitversion和maxbitversion
    分別對應的是currentversion還是expectedversion.
    """
    if len(currentversionBITS) >= len(expectedversionBITS):
        minbitversion = expectedversionBITS
        maxbitversion = currentversionBITS
    else:
        minbitversion = currentversionBITS
        maxbitversion = expectedversionBITS

    """
    逐位比較版本大小,按最小位循環,這個循環之后將會找出版本號最大的,而且這里必須讓這個循環完成。這里和之前的算法不同。
    再多說一句,這里你也可以按照最大位循環,但是你就需要考慮異常,從程序性能角度來說盡量不要使用異常控制邏輯,除非沒有更好的選擇。
    """
    for index, bit in enumerate(minbitversion):
        try:
            if int(bit) > int(maxbitversion[index]):
                MAX_VERSION = ".".join(minbitversion)
                break
            elif int(bit) < int(maxbitversion[index]):
                MAX_VERSION = ".".join(maxbitversion)
                break
            else:
                MAX_VERSION = ".".join(maxbitversion)
        except IndexError as err:
            pass

    # 這里則用於找到當前的 MAX_VERSION 到底是currentversion還是expectedversion,只有找到了才能給出建議是忽略還是升級。
    # 之前那種算法里沒有,因為通過位數補全之后比較不存在一段數據不清狀態。
    if MAX_VERSION == currentversion:
        CODE = 88
    else:
        CODE = 99

    return CODE, MAX_VERSION


def main():
    print checkVersionG2("1.0", "1.1")  # 正確的返回 99 1.1
    print checkVersionG2("1.1.2", "1.1")  # 正確的返回 88 1.1.2
    print checkVersionG2("1.11.3", "1.11.24")  # 正確的返回 99 1.11.24
    print checkVersionG2("1.0.11.3", "1.0.11.2")  # 正確的返回 88 1.0.11.3

if __name__ == "__main__":
    try:
        main()
    finally:
        sys.exit()

執行結果

總結

上面只是用了Python的實現,算法通用。這兩個方法里面沒有對版本號格式的檢驗簡易增加,通過正則就可以。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM