programing

Swift에서 두 버전 문자열 비교

javamemo 2023. 9. 7. 21:27
반응형

Swift에서 두 버전 문자열 비교

저는 두 개의 다른 앱 버전 Strings(즉, "3.0.1"과 "3.0.2")를 가지고 있습니다.

스위프트를 이용해서 어떻게 비교할 수 있습니까?

결국 Strings를 NSSstrings로 변환해야 했습니다.

if storeVersion.compare(currentVersion, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending {
       println("store version is newer")
}

스위프트 3

let currentVersion = "3.0.1"
let storeVersion = "3.0.2"

if storeVersion.compare(currentVersion, options: .numeric) == .orderedDescending {
    print("store version is newer")
}

NSSstring으로 섭외할 필요는 없습니다.스위프트 3의 문자열 객체는 아래와 같은 버전을 비교할 수 있을 정도로 강력합니다.

let version = "1.0.0"
let targetVersion = "0.5.0"

version.compare(targetVersion, options: .numeric) == .orderedSame        // false
version.compare(targetVersion, options: .numeric) == .orderedAscending   // false
version.compare(targetVersion, options: .numeric) == .orderedDescending  // true

그러나 위의 샘플은 0이 추가된 버전은 포함하지 않습니다.(예: "1.0.0" & "1.0")

그래서 저는 스위프트를 이용하여 버전 비교를 처리하기 위해 String에서 이러한 확장 방법을 모두 만들었습니다.제가 말씀드린 0을 추가로 고려한 것은 맞지만, 아주 간단하며 예상하신 대로 작동할 것입니다.

XCTAssertTrue(UIDevice.current.systemVersion.isVersion(lessThan: "99.0.0"))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(equalTo: UIDevice.current.systemVersion))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(greaterThan: "3.5.99"))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(lessThanOrEqualTo: "13.5.99"))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(greaterThanOrEqualTo: UIDevice.current.systemVersion))
XCTAssertTrue("0.1.1".isVersion(greaterThan: "0.1"))
XCTAssertTrue("0.1.0".isVersion(equalTo: "0.1"))
XCTAssertTrue("10.0.0".isVersion(equalTo: "10"))
XCTAssertTrue("10.0.1".isVersion(equalTo: "10.0.1"))
XCTAssertTrue("5.10.10".isVersion(lessThan: "5.11.5"))
XCTAssertTrue("1.0.0".isVersion(greaterThan: "0.99.100"))
XCTAssertTrue("0.5.3".isVersion(lessThanOrEqualTo: "1.0.0"))
XCTAssertTrue("0.5.29".isVersion(greaterThanOrEqualTo: "0.5.3"))

그냥 보고 내 샘플 확장 저장소에 원하는 것을 가져가면 됩니다. 신경 쓸 자격증도 없이 말이죠.

https://github.com/DragonCherry/VersionCompare

스위프트 4+

let current = "1.3"
let appStore = "1.2.9"
let versionCompare = current.compare(appStore, options: .numeric)
if versionCompare == .orderedSame {
    print("same version")
} else if versionCompare == .orderedAscending {
    // will execute the code here
    print("ask user to update")
} else if versionCompare == .orderedDescending {
    // execute if current > appStore
    print("don't expect happen...")
}

스위프트 3 버전

let storeVersion = "3.14.10"
let currentVersion = "3.130.10"

extension String {
    func versionToInt() -> [Int] {
        return self.components(separatedBy: ".")
            .map { Int.init($0) ?? 0 }
    }
}
//true
storeVersion.versionToInt().lexicographicallyPrecedes(currentVersion.versionToInt())

스위프트 2 버전 비교

let storeVersion = "3.14.10"

let currentVersion = "3.130.10"
extension String {
    func versionToInt() -> [Int] {
      return self.componentsSeparatedByString(".")
          .map {
              Int.init($0) ?? 0
          }
    }
}

// true
storeVersion.versionToInt().lexicographicalCompare(currentVersion.versionToInt()) 

다음이 제게 도움이 됩니다.

extension String {

  static func ==(lhs: String, rhs: String) -> Bool {
    return lhs.compare(rhs, options: .numeric) == .orderedSame
  }

  static func <(lhs: String, rhs: String) -> Bool {
    return lhs.compare(rhs, options: .numeric) == .orderedAscending
  }

  static func <=(lhs: String, rhs: String) -> Bool {
    return lhs.compare(rhs, options: .numeric) == .orderedAscending || lhs.compare(rhs, options: .numeric) == .orderedSame
  }

  static func >(lhs: String, rhs: String) -> Bool {
    return lhs.compare(rhs, options: .numeric) == .orderedDescending
  }

  static func >=(lhs: String, rhs: String) -> Bool {
    return lhs.compare(rhs, options: .numeric) == .orderedDescending || lhs.compare(rhs, options: .numeric) == .orderedSame
  }

}


"1.2.3" == "1.2.3" // true
"1.2.3" > "1.2.3" // false
"1.2.3" >= "1.2.3" // true
"1.2.3" < "1.2.3" // false
"1.2.3" <= "1.2.3" // true

"3.0.0" >= "3.0.0.1" // false
"3.0.0" > "3.0.0.1" // false
"3.0.0" <= "3.0.0.1" // true
"3.0.0.1" >= "3.0.0.1" // true
"3.0.1.1.1.1" >= "3.0.2" // false
"3.0.15" > "3.0.1.1.1.1" // true
"3.0.10" > "3.0.100.1.1.1" // false
"3.0.1.1.1.3.1.7" == "3.0.1.1.1.3.1" // false
"3.0.1.1.1.3.1.7" > "3.0.1.1.1.3.1" // true

"3.14.10" == "3.130.10" // false
"3.14.10" > "3.130.10" // false
"3.14.10" >= "3.130.10" // false
"3.14.10" < "3.130.10" // true
"3.14.10" <= "3.130.10" // true

enter image description here

아쇼크 버전과 드래곤 체리를 섞었습니다.

// MARK: - Version comparison

extension String {

    // Modified from the DragonCherry extension - https://github.com/DragonCherry/VersionCompare
    private func compare(toVersion targetVersion: String) -> ComparisonResult {
        let versionDelimiter = "."
        var result: ComparisonResult = .orderedSame
        var versionComponents = components(separatedBy: versionDelimiter)
        var targetComponents = targetVersion.components(separatedBy: versionDelimiter)

        while versionComponents.count < targetComponents.count {
            versionComponents.append("0")
        }

        while targetComponents.count < versionComponents.count {
            targetComponents.append("0")
        }

        for (version, target) in zip(versionComponents, targetComponents) {
            result = version.compare(target, options: .numeric)
            if result != .orderedSame {
                break
            }
        }

        return result
    }

    func isVersion(equalTo targetVersion: String) -> Bool { return compare(toVersion: targetVersion) == .orderedSame }

    func isVersion(greaterThan targetVersion: String) -> Bool { return compare(toVersion: targetVersion) == .orderedDescending }

    func isVersion(greaterThanOrEqualTo targetVersion: String) -> Bool { return compare(toVersion: targetVersion) != .orderedAscending }

    func isVersion(lessThan targetVersion: String) -> Bool { return compare(toVersion: targetVersion) == .orderedAscending }

    func isVersion(lessThanOrEqualTo targetVersion: String) -> Bool { return compare(toVersion: targetVersion) != .orderedDescending }

    static func ==(lhs: String, rhs: String) -> Bool { lhs.compare(toVersion: rhs) == .orderedSame }

    static func <(lhs: String, rhs: String) -> Bool { lhs.compare(toVersion: rhs) == .orderedAscending }

    static func <=(lhs: String, rhs: String) -> Bool { lhs.compare(toVersion: rhs) != .orderedDescending }

    static func >(lhs: String, rhs: String) -> Bool { lhs.compare(toVersion: rhs) == .orderedDescending }

    static func >=(lhs: String, rhs: String) -> Bool { lhs.compare(toVersion: rhs) != .orderedAscending }

}

사용방법:

"1.2.3" == "1.2.3" // true
"1.2.3" > "1.2.3" // false
"1.2.3" >= "1.2.3" // true
"1.2.3" < "1.2.3" // false
"1.2.3" <= "1.2.3" // true

"3.0.0" >= "3.0.0.1" // false
"3.0.0" > "3.0.0.1" // false
"3.0.0" <= "3.0.0.1" // true
"3.0.0.1" >= "3.0.0.1" // true
"3.0.1.1.1.1" >= "3.0.2" // false
"3.0.15" > "3.0.1.1.1.1" // true
"3.0.10" > "3.0.100.1.1.1" // false
"3.0.1.1.1.3.1.7" == "3.0.1.1.1.3.1" // false
"3.0.1.1.1.3.1.7" > "3.0.1.1.1.3.1" // true

"3.14.10" == "3.130.10" // false
"3.14.10" > "3.130.10" // false
"3.14.10" >= "3.130.10" // false
"3.14.10" < "3.130.10" // true
"3.14.10" <= "3.130.10" // true

"0.1.1".isVersion(greaterThan: "0.1")
"0.1.0".isVersion(equalTo: "0.1")
"10.0.0".isVersion(equalTo: "10")
"10.0.1".isVersion(equalTo: "10.0.1")
"5.10.10".isVersion(lessThan: "5.11.5")
"1.0.0".isVersion(greaterThan: "0.99.100")
"0.5.3".isVersion(lessThanOrEqualTo: "1.0.0")
"0.5.29".isVersion(greaterThanOrEqualTo: "0.5.3")

Swift 3을 사용하면 비교 함수를 사용하여 응용 프로그램 버전 문자열을 숫자로 설정한 옵션과 비교할 수 있습니다.

문자열 프로그래밍 가이드는 Apple Developers의 설명서에서 Objective-C의 작동 방식에 대한 예시를 읽어 보십시오.

저는 https://iswift.org/playground 에서 이것들을 시도했습니다.

print("2.0.3".compare("2.0.4", options: .numeric))//orderedAscending
print("2.0.3".compare("2.0.5", options: .numeric))//orderedAscending

print("2.0.4".compare("2.0.4", options: .numeric))//orderedSame

print("2.0.4".compare("2.0.3", options: .numeric))//orderedDescending
print("2.0.5".compare("2.0.3", options: .numeric))//orderedDescending

print("2.0.10".compare("2.0.11", options: .numeric))//orderedAscending
print("2.0.10".compare("2.0.20", options: .numeric))//orderedAscending

print("2.0.0".compare("2.0.00", options: .numeric))//orderedSame
print("2.0.00".compare("2.0.0", options: .numeric))//orderedSame

print("2.0.20".compare("2.0.19", options: .numeric))//orderedDescending
print("2.0.99".compare("2.1.0", options: .numeric))//orderedAscending

도움이 되기를 바랍니다!

라이브러리를 사용하는 것을 좋아한다면, 바퀴를 다시 만들지 말고 이것을 사용하세요.https://github.com/zenangst/Versions

않은 예를 들어, storeVersion is storeVersion의 길이는 다음과 같습니다. 예를 들어 storeVersion 은3.0.0, 하지만 당신은 버그를 고쳐서 이름을 지었습니다.3.0.0.1.

func ascendingOrSameVersion(minorVersion smallerVersion:String, largerVersion:String)->Bool{
    var result = true //default value is equal

    let smaller = split(smallerVersion){ $0 == "." }
    let larger = split(largerVersion){ $0 == "." }

    let maxLength = max(smaller.count, larger.count)

    for var i:Int = 0; i < maxLength; i++ {
        var s = i < smaller.count ? smaller[i] : "0"
        var l = i < larger.count ? larger[i] : "0"
        if s != l {
            result = s < l
            break
        }
    }
    return result
}

String.compare' 방법으로 할 수 있습니다.비교 결과를 사용하여 버전이 더 크거나, 더 작거나 같은 시기를 식별합니다.

예:

"1.1.2".compare("1.1.1").rawValue -> ComparisonResult.orderedDescending
"1.1.2".compare("1.1.2").rawValue -> ComparisonResult.orderedSame
"1.1.2".compare("1.1.3").rawValue -> ComparisonResult.orderedAscending

이를 위해 Swift 3 클래스를 작성했습니다.

class VersionString: NSObject {

    // MARK: - Properties
    var string = ""
    override var description: String {
        return string
    }

    // MARK: - Initialization
    private override init() {
        super.init()
    }
    convenience init(_ string: String) {
        self.init()
        self.string = string
    }

    func compare(_ rhs: VersionString) -> ComparisonResult {
        return string.compare(rhs.string, options: .numeric)
    }

    static func ==(lhs: VersionString, rhs: VersionString) -> Bool {
        return lhs.compare(rhs) == .orderedSame
    }

    static func <(lhs: VersionString, rhs: VersionString) -> Bool {
        return lhs.compare(rhs) == .orderedAscending
    }

    static func <=(lhs: VersionString, rhs: VersionString) -> Bool {
        return lhs.compare(rhs) == .orderedAscending || lhs.compare(rhs) == .orderedSame
    }

    static func >(lhs: VersionString, rhs: VersionString) -> Bool {
        return lhs.compare(rhs) == .orderedDescending
    }

    static func >=(lhs: VersionString, rhs: VersionString) -> Bool {
        return lhs.compare(rhs) == .orderedDescending || lhs.compare(rhs) == .orderedSame
    }
}

let v1 = VersionString("1.2.3")
let v2 = VersionString("1.2.3")

print("\(v1) == \(v2): \(v1 == v2)") // 1.2.3 == 1.2.3: true
print("\(v1) >  \(v2): \(v1 > v2)")  // 1.2.3 >  1.2.3: false
print("\(v1) >= \(v2): \(v1 >= v2)") // 1.2.3 >= 1.2.3: true
print("\(v1) <  \(v2): \(v1 < v2)")  // 1.2.3 <  1.2.3: false
print("\(v1) <= \(v2): \(v1 <= v2)") // 1.2.3 <= 1.2.3: true

@DragonCherry 솔루션이 좋습니다!

그런데 아쉽게도 버전이.1.0.1.2(나도 알아요, 존재하면 안 되지만, 일들이 일어나요.)

내선번호를 바꾸고 모든 경우를 처리할 수 있도록 테스트를 개선했습니다.또한 버전 문자열에서 불필요한 문자를 모두 제거하는 확장자를 만들었습니다. 경우에 따라서는v1.0.1.2.

다음 gists에서 모든 코드를 확인할 수 있습니다.

  • 문자열 확장명 - https://gist.github.com/endy-s/3791fe5c856cccaabff331fd49356dbf
  • 테스트 - https://gist.github.com/endy-s/7cacaa730bf9fd5abf6021e58e962191

누구에게나 도움이 되었으면 좋겠습니다 :)

프로젝트를 위해 하위 클래스를 만들게 되었습니다.누군가에게 도움이 될 경우를 대비해 여기에 공유하는 것.건배...!!!

import Foundation

final class AppVersionComparator {

var currentVersion: String

init() {
    let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
    self.currentVersion = version ?? ""
}

func compareVersions(lhs: String, rhs: String) -> ComparisonResult {
    let comparisonResult = lhs.compare(rhs, options: .numeric)
    return comparisonResult
}

/**
 - If lower bound is present perform lowerBound check
 - If upper bound is present perform upperBound check
 - Return true if both are nil
 */
func fallsInClosedRange(lowerBound: String?, upperBound: String?) -> Bool {
    if let lowerBound = lowerBound {
        let lowerBoundComparisonResult = compareVersions(lhs: currentVersion, rhs: lowerBound)
        guard lowerBoundComparisonResult == .orderedSame || lowerBoundComparisonResult == .orderedDescending else { return false }
    }
    if let upperBound = upperBound {
        let upperBoundComparisonResult = compareVersions(lhs: currentVersion, rhs: upperBound)
        guard upperBoundComparisonResult == .orderedSame || upperBoundComparisonResult == .orderedAscending else { return false }
    }
    return true
}

/**
 - If lower bound is present perform lowerBound check
 - If upper bound is present perform upperBound check
 - Return true if both are nil
 */
func fallsInOpenRange(lowerBound: String?, upperBound: String?) -> Bool {
    if let lowerBound = lowerBound {
        let lowerBoundComparisonResult = compareVersions(lhs: currentVersion, rhs: lowerBound)
        guard lowerBoundComparisonResult == .orderedDescending else { return false }
    }
    if let upperBound = upperBound {
        let upperBoundComparisonResult = compareVersions(lhs: currentVersion, rhs: upperBound)
        guard upperBoundComparisonResult == .orderedAscending else { return false }
    }
    return true
}

func isCurrentVersionGreaterThan(version: String) -> Bool {
    let result = compareVersions(lhs: currentVersion, rhs: version)
    return result == .orderedDescending
}

func isCurrentVersionLessThan(version: String) -> Bool {
    let result = compareVersions(lhs: currentVersion, rhs: version)
    return result == .orderedAscending
}

func isCurrentVersionEqualsTo(version: String) -> Bool {
    let result = compareVersions(lhs: currentVersion, rhs: version)
    return result == .orderedSame
}}

일부 테스트 사례도 있습니다.

import XCTest

class AppVersionComparatorTests: XCTestCase {

var appVersionComparator: AppVersionComparator!

override func setUp() {
    super.setUp()
    self.appVersionComparator = AppVersionComparator()
}

func testInit() {
    XCTAssertFalse(appVersionComparator.currentVersion.isEmpty)
}

func testCompareEqualVersions() {
    let testVersions = [VersionComparisonModel(lhs: "1.2.1", rhs: "1.2.1"),
                        VersionComparisonModel(lhs: "1.0", rhs: "1.0"),
                        VersionComparisonModel(lhs: "1.0.2", rhs: "1.0.2"),
                        VersionComparisonModel(lhs: "0.1.1", rhs: "0.1.1"),
                        VersionComparisonModel(lhs: "3.2.1", rhs: "3.2.1")]
    for model in testVersions {
        let result = appVersionComparator.compareVersions(lhs: model.lhs, rhs: model.rhs)
        XCTAssertEqual(result, .orderedSame)
    }
}

func testLHSLessThanRHS() {
    let lhs = "1.2.0"
    let rhs = "1.2.1"
    let result = appVersionComparator.compareVersions(lhs: lhs, rhs: rhs)
    XCTAssertEqual(result, .orderedAscending)
}

func testInvalidRange() {
    let isCurrentVersionInClosedRange = appVersionComparator.currentVersionFallsInClosedRange(lowerBound: "", upperBound: "")
    XCTAssertFalse(isCurrentVersionInClosedRange)
    let isCurrentVersionInOpenRange = appVersionComparator.currentVersionFallsInOpenRange(lowerBound: "", upperBound: "")
    XCTAssertFalse(isCurrentVersionInOpenRange)
}

func testCurrentInClosedRangeSuccess() {
    appVersionComparator.currentVersion = "1.2.1"
    let isCurrentVersionInClosedRange = appVersionComparator.currentVersionFallsInClosedRange(lowerBound: "1.2.0", upperBound: "1.2.1")
    XCTAssert(isCurrentVersionInClosedRange)
}

func testIsCurrentVersionGreaterThanGivenVersion() {
    appVersionComparator.currentVersion = "1.4.2"
    let result = appVersionComparator.isCurrentVersionGreaterThan(version: "1.2")
    XCTAssert(result)
}

func testIsCurrentVersionLessThanGivenVersion() {
    appVersionComparator.currentVersion = "1.4.2"
    let result = appVersionComparator.isCurrentVersionLessThan(version: "1.5")
    XCTAssert(result)
}

func testIsCurrentVersionEqualsToGivenVersion() {
    appVersionComparator.currentVersion = "1.4.2"
    let result = appVersionComparator.isCurrentVersionEqualsTo(version: "1.4.2")
    XCTAssert(result)
}}

Mock Model:

struct VersionComparisonModel {

let lhs: String

let rhs: String 

}

당신이 사용하는.NSString올바른 방법이지만, 재미를 위한 비파운데이션 시도가 있습니다.

let storeVersion = "3.14.10"

let currentVersion = "3.130.10"

func versionToArray(version: String) -> [Int] {
    return split(version) {
        $0 == "."
    }.map {
        // possibly smarter ways to do this
        $0.toInt() ?? 0
    }
}

storeVersion < currentVersion  // false

// true
lexicographicalCompare(versionToArray(storeVersion), versionToArray(currentVersion))
extension String {

    func compareVersionNumbers(other: String) -> Int {
        
        let nums1 = self.split(separator: ".").map({ Int($0) ?? 0 })
        let nums2 = other.split(separator: ".").map({ Int($0) ?? 0 })
        
        for i in 0..<max(nums1.count, nums2.count) {
            
            let num1 = i < nums1.count ? nums1[i] : 0
            let num2 = i < nums2.count ? nums2[i] : 0
            
            if num1 != num2 {
                return num1 - num2
            }
        }
        
        return 0
    }
}

여기 간단한 구조물이 있습니다.

public struct VersionString: Comparable {

    public let rawValue: String

    public init(_ rawValue: String) {
        self.rawValue = rawValue
    }

    public static func == (lhs: VersionString, rhs: VersionString) -> Bool {
        return lhs.rawValue.compare(rhs.rawValue, options: .numeric) == .orderedSame
    }

    public static func < (lhs: VersionString, rhs: VersionString) -> Bool {
        return lhs.rawValue.compare(rhs.rawValue, options: .numeric) == .orderedAscending
    }
}

좋은 답변이 많이 나온 것을 이해할 수 있습니다.앱 버전을 비교한 제 버전은 다음과 같습니다.

func compareVersions(installVersion: String, storeVersion: String) -> Bool{
        // 1.7.5
        var installedArr = installVersion.components(separatedBy: ".")
        var storeArr = storeVersion.components(separatedBy: ".")
        var isAvailable = false

        while(installedArr.count < storeArr.count){
            installedArr.append("0")
        }

        while(storeArr.count < installedArr.count){
            storeArr.append("0")
        }

        for index in 0 ..< installedArr.count{
            if let storeIndex=storeArr[index].toInt(), let installIndex=installedArr[index].toInt(){
                if storeIndex > installIndex{
                    isAvailable = true
                    return isAvailable
                }
            }
        }

        return isAvailable
    }

다음은 비교와 같은 버전 형식의 모든 경우를 다루기 위한 나의 노력입니다."10.0"와 함께"10.0.1", 제가 놓친 사건이 있으면 알려주세요.

주요 내용은 https://gist.github.com/shamzahasan88/bc22af2b7c96b6a06a064243a02c8bcc 입니다.모두에게 도움이 되길 바랍니다.

그리고 여기 내 요지를 평가하고 싶지 않은 사람이 있다면 코드가 있습니다 :P

extension String {

  // Version format "12.34.39" where "12" is "Major", "34" is "Minor" and "39" is "Bug fixes"
  // "maximumDigitCountInVersionComponent" is optional parameter determines the maximum length of "Maajor", "Minor" and "Bug Fixes" 
  func shouldUpdateAsCompareToVersion(storeVersion: String, maximumDigitCountInVersionComponent: Int = 5) -> Bool {
        let adjustTralingZeros: (String, Int)->String = { val, count in
            return "\(val)\((0..<(count)).map{_ in "0"}.joined(separator: ""))"
        }
        let adjustLength: ([String.SubSequence], Int)->[String] = { strArray, count in
            return strArray.map {adjustTralingZeros("\($0)", count-$0.count)}
        }
        let storeVersionSubSequence = storeVersion.split(separator: ".")
        let currentVersionSubSequence = self.split(separator: ".")
        let formatter = NumberFormatter()
        formatter.minimumIntegerDigits = maximumDigitCountInVersionComponent
        formatter.maximumIntegerDigits = maximumDigitCountInVersionComponent
        let storeVersions = adjustLength(storeVersionSubSequence, maximumDigitCountInVersionComponent)
        let currentVersions = adjustLength(currentVersionSubSequence, maximumDigitCountInVersionComponent)
        var storeVersionString = storeVersions.joined(separator: "")
        var currentVersionString = currentVersions.joined(separator: "")
        let diff = storeVersionString.count - currentVersionString.count

        if diff > 0 {
            currentVersionString = adjustTralingZeros(currentVersionString, diff)
        }else if diff < 0 {
            storeVersionString = adjustTralingZeros(storeVersionString, -diff)
        }
        let literalStoreVersion = Int(storeVersionString)!
        let literalCurrentVersion = Int(currentVersionString)!
        return literalCurrentVersion < literalStoreVersion
    }
}

용도:

print("33.29".shouldUpdateAsCompareToVersion(storeVersion: "34.23.19")) // true
print("35.29".shouldUpdateAsCompareToVersion(storeVersion: "34.23.19")) // false
print("34.23.2".shouldUpdateAsCompareToVersion(storeVersion: "34.23.19")) // false
print("34.23.18".shouldUpdateAsCompareToVersion(storeVersion: "34.23.19")) // true
extension String {
    func versionCompare(_ otherVersion: String) -> ComparisonResult {
        let versionDelimiter = "."

        var versionComponents = self.components(separatedBy: versionDelimiter) // <1>
        var otherVersionComponents = otherVersion.components(separatedBy: versionDelimiter)

        let zeroDiff = versionComponents.count - otherVersionComponents.count // <2>

        if zeroDiff == 0 { // <3>
            // Same format, compare normally
            return self.compare(otherVersion, options: .literal)
        } else {
            let zeros = Array(repeating: "0", count: abs(zeroDiff)) // <4>
            if zeroDiff > 0 {
                otherVersionComponents.append(contentsOf: zeros) // <5>
            } else {
                versionComponents.append(contentsOf: zeros)
            }
            return versionComponents.joined(separator: versionDelimiter)
                .compare(otherVersionComponents.joined(separator: versionDelimiter), options: .literal) // <6>
        }
    }
}

//USAGE

let previousVersionNumber = "1.102.130"
let newAnpStoreVersion = "1.2" // <- Higher

switch previousVersionNumber.versionCompare(newAnpStoreVersion) {
case .orderedAscending:
case .orderedSame:
case .orderedDescending:
}

비동기/대기 코드화 전략

버전 문자열에서 점을 제거하면 간단한 Int 비교가 됩니다.

가정/동굴:Version String은 항상 같은 자릿수입니다(예를 들어 버전 1.10.0이 있는 경우 1110으로 변환되고 버전 2.1.0은 210으로 비교되므로 실패함).전공을 먼저 비교하고, 그 다음에 부전공을 비교하고, 다른 답안에서 언급한 다른 전략을 패치하거나 통합하여 결합하는 것은 큰 도약이 아닙니다.

// inner json (there are *many* more parameters, but this is the only one we're concerned with)
struct AppUpdateData: Codable {
    let version: String
}
// outer json
struct AppVersionResults: Codable {
    let results: [AppUpdateData]
}

struct AppVersionComparison {
    let currentVersion: Int
    let latestVersion: Int

    var needsUpdate: Bool {
        currentVersion < latestVersion
    }
}
// this isn't really doing much for error handling, could just return an optional
func needsUpdate() async throws -> AppVersionComparison {
    let bundleId = "com.my.bundleId"
    let url = URL(string: "https://itunes.apple.com/lookup?bundleId=\(bundleId)")!
    let (data, _) = try await URLSession.shared.data(from: url)

    let noResultsError: NSError = NSError(domain: #function, code: 999, userInfo: [NSLocalizedDescriptionKey: "No results"])
    do {
        let decoder = JSONDecoder()
        let decoded = try decoder.decode(AppVersionResults.self, from: data)
        guard decoded.results.count > 0 else { throw noResultsError }

        var latestVersionString = decoded.results[0].version
        latestVersionString.removeAll { $0 == "." }

        guard let latestVersion = Int(latestVersionString),
              var currentVersionString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
        else { throw noResultsError }

        currentVersionString.removeAll { $0 == "." }
        guard let currentVersion = Int(currentVersionString) else {
            throw noResultsError
        }

        return .init(currentVersion: currentVersion, latestVersion: latestVersion)
    }
}

이거 어때:

class func compareVersion(_ ver: String, to toVer: String) -> ComparisonResult {
    var ary0 = ver.components(separatedBy: ".").map({ return Int($0) ?? 0 })
    var ary1 = toVer.components(separatedBy: ".").map({ return Int($0) ?? 0 })
    while ary0.count < 3 {
        ary0.append(0)
    }
    while ary1.count < 3 {
        ary1.append(0)
    }
    let des0 = ary0[0...2].description
    let des1 = ary1[0...2].description
    return des0.compare(des1, options: .numeric)
}

테스트:

func test_compare_version() {
    XCTAssertEqual(compareVersion("1.0.0", to: "1.0.0"), .orderedSame)
    XCTAssertEqual(compareVersion("1.0.0", to: "1.0."), .orderedSame)
    XCTAssertEqual(compareVersion("1.0.0", to: "1.0"), .orderedSame)
    XCTAssertEqual(compareVersion("1.0.0", to: "1."), .orderedSame)
    XCTAssertEqual(compareVersion("1.0.0", to: "1"), .orderedSame)
    XCTAssertEqual(compareVersion("1.0.0", to: "1.0.1"), .orderedAscending)
    XCTAssertEqual(compareVersion("1.0.0", to: "1.1."), .orderedAscending)
    XCTAssertEqual(compareVersion("1.0.0", to: "1.1"), .orderedAscending)
    XCTAssertEqual(compareVersion("1.0.0", to: "2."), .orderedAscending)
    XCTAssertEqual(compareVersion("1.0.0", to: "2"), .orderedAscending)

    XCTAssertEqual(compareVersion("1.0.0", to: "1.0.0"), .orderedSame)
    XCTAssertEqual(compareVersion("1.0.", to: "1.0.0"), .orderedSame)
    XCTAssertEqual(compareVersion("1.0", to: "1.0.0"), .orderedSame)
    XCTAssertEqual(compareVersion("1.", to: "1.0.0"), .orderedSame)
    XCTAssertEqual(compareVersion("1", to: "1.0.0"), .orderedSame)
    XCTAssertEqual(compareVersion("1.0.1", to: "1.0.0"), .orderedDescending)
    XCTAssertEqual(compareVersion("1.1.", to: "1.0.0"), .orderedDescending)
    XCTAssertEqual(compareVersion("1.1", to: "1.0.0"), .orderedDescending)
    XCTAssertEqual(compareVersion("2.", to: "1.0.0"), .orderedDescending)
    XCTAssertEqual(compareVersion("2", to: "1.0.0"), .orderedDescending)

    XCTAssertEqual(compareVersion("1.0.0", to: "0.9.9"), .orderedDescending)
    XCTAssertEqual(compareVersion("1.0.0", to: "0.9."), .orderedDescending)
    XCTAssertEqual(compareVersion("1.0.0", to: "0.9"), .orderedDescending)
    XCTAssertEqual(compareVersion("1.0.0", to: "0."), .orderedDescending)
    XCTAssertEqual(compareVersion("1.0.0", to: "0"), .orderedDescending)

    XCTAssertEqual(compareVersion("", to: "0"), .orderedSame)
    XCTAssertEqual(compareVersion("0", to: ""), .orderedSame)
    XCTAssertEqual(compareVersion("", to: "1"), .orderedAscending)
    XCTAssertEqual(compareVersion("1", to: ""), .orderedDescending)

    XCTAssertEqual(compareVersion("1.0.0", to: "1.0.0.9"), .orderedSame)
    XCTAssertEqual(compareVersion("1.0.0.9", to: "1.0.0"), .orderedSame)
}

언급URL : https://stackoverflow.com/questions/27932408/compare-two-version-strings-in-swift

반응형