Ich habe zwei verschiedene App-Versionszeichenfolgen (dh "3.0.1" und "3.0.2").
Wie kann man diese mit Swift vergleichen ?
Antworten:
Ich musste meine Strings in NSStrings konvertieren:
if storeVersion.compare(currentVersion, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending {
println("store version is newer")
}
Swift 3
let currentVersion = "3.0.1"
let storeVersion = "3.0.2"
if storeVersion.compare(currentVersion, options: .numeric) == .orderedDescending {
print("store version is newer")
}
extension String { func isVersionNewer(compareVersion: String) -> Bool { if self.compare(compareVersion, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending { return true } return false }
if storeVersion.compare(currentVersion, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedDescending { NSLog("store version is newer") }
Sie müssen es nicht als NSString umwandeln. Das String-Objekt in Swift 3 ist gerade leistungsfähig genug, um Versionen wie unten zu vergleichen.
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
Das obige Beispiel deckt jedoch keine Versionen mit zusätzlichen Nullen ab (Beispiel: "1.0.0" & "1.0").
Daher habe ich alle Arten dieser Erweiterungsmethoden in String erstellt, um den Versionsvergleich mit Swift durchzuführen. Es berücksichtigt zusätzliche Nullen, die ich gesagt habe, ziemlich einfach und wird wie erwartet funktionieren.
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"))
Werfen Sie einen Blick darauf und nehmen Sie alles, was Sie wollen, in mein Beispiel-Erweiterungs-Repository, ohne dass Sie sich um eine Lizenz kümmern müssen.
1.0.1.2
(ich weiß, es sollte existieren, aber es passiert etwas). Ich habe Ihre Erweiterung geändert und die Tests verbessert, um (glaube ich) alle Fälle abzudecken. Außerdem habe ich eine Erweiterung erstellt, die alle unnötigen Zeichen aus der Versionszeichenfolge entfernt. Manchmal kann dies der Fall sein v1.0.1.2
. Sie können alle den Code in den folgenden Logen überprüfen: String - Erweiterung - gist.github.com/endy-s/3791fe5c856cccaabff331fd49356dbf Tests - gist.github.com/endy-s/7cacaa730bf9fd5abf6021e58e962191 Hoffnung , es hilft jemand :)
Swift 3 Version
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())
Swift 2 Version vergleichen
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())
Swift 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...")
}
Folgendes funktioniert für mich:
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
Manchmal entspricht die Länge der storeVersion nicht der Länge der currentVersion. Beispiel: storeVersion ist 3.0.0
jedoch, dass Sie einen Fehler behoben und benannt haben 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
}
Mit Swift 3 können Anwendungsversionszeichenfolgen mithilfe der Vergleichsfunktion mit der auf numerisch eingestellten Option verglichen werden.
In diesem String-Programmierhandbuch aus der Dokumentation der Apple-Entwickler finden Sie Beispiele für die Funktionsweise von Objective-C.
Ich habe diese unter https://iswift.org/playground ausprobiert
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
Hoffentlich hilft das!
Wenn Sie Bibliotheken verwenden möchten, verwenden Sie diese, und erfinden Sie das Rad nicht neu. https://github.com/zenangst/Versions
Sie können dies mit der Methode 'String.compare' tun. Verwenden Sie ComparisonResult, um festzustellen, wann Ihre Version größer, gleich oder kleiner ist.
Beispiel:
"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
Schrieb eine kleine Swift 3 Klasse, um dies zu tun:
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-Lösung ist großartig!
Aber leider funktioniert es nicht, wenn die Version so ist 1.0.1.2
(ich weiß, es sollte nicht existieren, aber es passiert etwas).
Ich habe Ihre Erweiterung geändert und die Tests verbessert, um (glaube ich) alle Fälle abzudecken. Außerdem habe ich eine Erweiterung erstellt, die alle unnötigen Zeichen aus der Versionszeichenfolge entfernt. Manchmal kann dies der Fall seinv1.0.1.2
.
Sie können den gesamten Code in den folgenden Abschnitten überprüfen:
Hoffe es hilft jedem :)
Ich habe die Ashok-Version und DragonCherry gemischt:
// 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 }
}
Verwenden von:
"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")
Ihre Verwendung von NSString
ist der richtige Weg, aber hier ist ein Nicht-Foundation-Versuch zum Spaß:
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))
Hier ist eine einfache schnelle Struktur
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
}
}
Wie wäre es damit:
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)
}
und testen:
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)
}
Ich kann verstehen, dass es viele gute Antworten gibt. Hier ist meine Version des Vergleichs der App-Version.
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
}
Hier ist mein Bemühen, alle Fälle von Versionsformaten wie Vergleichen "10.0"
mit abzudecken. "10.0.1"
Lassen Sie mich wissen, wenn ich einen Fall verpasst habe.
Hier ist der Kern https://gist.github.com/shamzahasan88/bc22af2b7c96b6a06a064243a02c8bcc . Hoffe es hilft allen.
Und hier ist der Code, wenn jemand meinen Kern nicht bewerten möchte: 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
}
}
Verwendung:
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 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
}
}