Compare version strings in groovy

2020-01-29 15:14发布

Hey I have created a Groovy script that will extract the version numbers of some folder. I would then like to compare the version numbers and select the highest.

I got my script to run through the dir folder and I then get the versions in this format: 02.2.02.01

So I could get something like this:

  • 02.2.02.01
  • 02.2.02.02
  • 02.2.03.01

I don't have them as a list but like this:

baseDir.listFiles().each { file -> 
  def string = file.getName().substring(5, 15)
  // do stuff
}

Also I have tested that Groovy could compare them with the > operator and it can! But now I need to select the one with the highest version

11条回答
▲ chillily
2楼-- · 2020-01-29 15:33

I use gradle 4.1 in Android Studio 3.0 Beta 7. There is VersionNumber.java (under C:\Users\ssfang.gradle\wrapper\dists\gradle-4.1-all\bzyivzo6n839fup2jbap0tjew\gradle-4.1\src\core\org\gradle\util)

For example:

apply plugin: 'com.android.application'

try{ // undocumented
    println "${android.plugin.getSdkFolder().getAbsolutePath()}"
    // Since 1.3.1 or 1.5.0? android studio version or android gradle plugin?
    println "${android.getSdkDirectory().getAbsolutePath()}"
}catch (ignored){
}

// As of android gradle plugin v2.1.2
println android.sdkDirectory.path
println android.ndkDirectory.path
def buildToolsVer = new File(android.sdkDirectory.path, 'build-tools').listFiles().collect{ VersionNumber.parse(it.getName()) }.sort()
println buildToolsVer
printf('%s, %s\n',  buildToolsVer.head(), buildToolsVer.last().toString())

def String mostRecentVersion(List<String> versions) {
//   TreeMap<VersionNumber, String> verNum2StrMap = versions.collectEntries(new TreeMap(), { [VersionNumber.parse(it), it] })

//    TreeMap<VersionNumber, String> verNum2StrMap = versions.inject(new TreeMap()) { memo, entry ->
//        memo[VersionNumber.parse(entry)] = entry
//        memo
//    }

    TreeMap<VersionNumber, String> verNum2StrMap = versions.inject(new TreeMap()) { map, verStr ->
        map << [(VersionNumber.parse(verStr)): verStr]
    }

    // println verNum2StrMap.lastEntry().value
    verNum2StrMap.lastEntry().value
}

assert mostRecentVersion(['02.2.02.01', '02.2.02.02', '02.2.03.01']) == '02.2.03.01'
assert mostRecentVersion(['4', '2']) == '4'
assert mostRecentVersion(['4.1', '4']) == '4.1'
assert mostRecentVersion(['4.1', '5']) == '5'

android {
    compileSdkVersion 25
    buildToolsVersion "26.0.2"
    defaultConfig {
        applicationId "ss.xsigner"
        minSdkVersion 14
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        setProperty("archivesBaseName", "xsigner")
    }
}

--

enter image description here

enter image description here

查看更多
Anthone
3楼-- · 2020-01-29 15:34

Here is a modification of Tim's answer which takes two version strings and returns a boolean (true if the first is newer than the second)

String v1 = '02.2.01.02'
String v2 = '02.2.06.02'

boolean isMoreRecent( String a, String b ) {
    [a,b]*.tokenize('.')*.collect { it as int }.with { u, v ->
       Integer result = [u,v].transpose().findResult{ x,y -> x <=> y ?: null } ?: u.size() <=> v.size()
       return (result == 1)
    } 
}

assert !isMoreRecent(v1,v2)
assert isMoreRecent(v2,v1)​
查看更多
Evening l夕情丶
4楼-- · 2020-01-29 15:39

The code I am using with Jenkins ExtendedChoiceParameter (tolerant to non-integer fragments in the version string)

def vers = ['none']
new File(this.getBinding().getVariable('dir')).eachDir() { dir -> dirs.add(dir.getName()) }

vers.sort{x, y ->
  def xa = x.tokenize('._-'); def ya = y.tokenize('._-')
  def sz = Math.min(xa.size(), ya.size())
  for (int i = 0; i < sz; ++i) {
    def xs = xa[i]; def ys = ya[i];
    if (xs.isInteger() && ys.isInteger()) {
      def xn = xs.toInteger()
      def yn = ys.toInteger()
      if (xn != yn) { return xn <=> yn }
    } else if (xs != ys) {
      return xs <=> ys
    }
  }

  return xa.size() <=> ya.size()
}.reverse().join(',')
查看更多
三岁会撩人
5楼-- · 2020-01-29 15:40

Mine is the shortest! lol )

versions = versions.sort {a, b ->
  def a1 = a.tokenize('.')*.toInteger(), b1 = b.tokenize('.')*.toInteger()
  for (i in 0..<[a1.size(), b1.size()].min()) 
    if (a1[i] != b1[i]) return a1[i] <=> b1[i]
  0
}
查看更多
何必那么认真
6楼-- · 2020-01-29 15:40

If you just need to implement Comparable or Comparator interface here's the shortest solution I came up with based on the other answers:

    [first, second]*.tokenize('.').with { a, b ->
        [a, b].transpose().findResult { x, y -> x <=> y ?: null } ?: a.size() <=> b.size()
    }
查看更多
登录 后发表回答