Bagaimana Anda membandingkan dua versi Strings di Java?


156

Apakah ada idiom standar untuk membandingkan nomor versi? Saya tidak bisa begitu saja menggunakan String String compareTo karena saya belum tahu berapa jumlah maksimum rilis poin yang akan ada. Saya perlu membandingkan versi dan memiliki yang berikut ini berlaku:

1.0 < 1.1
1.0.1 < 1.1
1.9 < 1.10

Sudahkah Anda mencoba menghilangkan titik-titik dan mem-parsing string yang dihasilkan sebagai integer? Saat ini saya menggunakan sesuatu yang mirip dengan berikut: String version = "1.1.2".replace(".", ""); int number = Integer.parseInt(version); // = 112. Anda dapat membandingkan nomor dengan yang lain dan dengan demikian menemukan versi yang lebih baru. Selain itu Anda dapat memeriksa apakah versionstring cocok dengan beberapa pola tertentu ingin \\d+\\.\\d+\\.\\dmembuat hasilnya memiliki setidaknya 3 digit.
Terdaftar

4
@RegisteredUser Bagaimana ini akan bekerja dengan sesuatu seperti ini: 1.12.1 dan 1.1.34?
kojow7

Anda harus memastikan setiap bagian memiliki ukuran panjang yang sama. Jadi untuk membandingkan dua versi dari contoh Anda, mereka harus seperti ini: 1.12.01 dan 1.01.34. Di java Anda bisa mencapai ini dengan terlebih dahulu memisahkan .karakter dan membandingkan setiap elemen panjang. Setelah itu, masukkan semua elemen ke dalam satu string, lalu parse sebagai int dan kemudian bandingkan dengan versi lain yang telah dikonversi dengan cara yang sama
RegisteredUser

Hanya ingin berbagi bahwa ini bisa sangat pendek diimplementasikan di groovy stackoverflow.com/a/7737400/1195507
rvazquezglez

Jawaban:


59

Tokenisasi string dengan titik sebagai pembatas dan kemudian bandingkan terjemahan bilangan bulat berdampingan, mulai dari kiri.


1
Ini yang saya duga harus saya lakukan. Ini juga melibatkan pengulangan token dalam versi yang lebih pendek dari dua string versi. Terimakasih sudah mengkonfirmasi.
Bill the Lizard

38
dan jangan lupa Anda mungkin tidak selalu memiliki nomor saja. beberapa aplikasi akan menyertakan angka bangun, dan mungkin menyertakan hal-hal seperti 1.0.1b untuk beta / dll.
John Gardner

2
Bagaimana kamu melakukan ini?
Big McLargeHuge

Anda menulis regex yang membagi string menjadi bagian digit dan non-digit. Bandingkan bagian digit secara numerik dan bagian non-digit secara leksikografis. (mungkin juga terpecah pada titik-titik.)
toolforger

180

Solusi lain untuk pos lama ini (bagi mereka yang mungkin membantu):

public class Version implements Comparable<Version> {

    private String version;

    public final String get() {
        return this.version;
    }

    public Version(String version) {
        if(version == null)
            throw new IllegalArgumentException("Version can not be null");
        if(!version.matches("[0-9]+(\\.[0-9]+)*"))
            throw new IllegalArgumentException("Invalid version format");
        this.version = version;
    }

    @Override public int compareTo(Version that) {
        if(that == null)
            return 1;
        String[] thisParts = this.get().split("\\.");
        String[] thatParts = that.get().split("\\.");
        int length = Math.max(thisParts.length, thatParts.length);
        for(int i = 0; i < length; i++) {
            int thisPart = i < thisParts.length ?
                Integer.parseInt(thisParts[i]) : 0;
            int thatPart = i < thatParts.length ?
                Integer.parseInt(thatParts[i]) : 0;
            if(thisPart < thatPart)
                return -1;
            if(thisPart > thatPart)
                return 1;
        }
        return 0;
    }

    @Override public boolean equals(Object that) {
        if(this == that)
            return true;
        if(that == null)
            return false;
        if(this.getClass() != that.getClass())
            return false;
        return this.compareTo((Version) that) == 0;
    }

}

Version a = new Version("1.1");
Version b = new Version("1.1.1");
a.compareTo(b) // return -1 (a<b)
a.equals(b)    // return false

Version a = new Version("2.0");
Version b = new Version("1.9.9");
a.compareTo(b) // return 1 (a>b)
a.equals(b)    // return false

Version a = new Version("1.0");
Version b = new Version("1");
a.compareTo(b) // return 0 (a=b)
a.equals(b)    // return true

Version a = new Version("1");
Version b = null;
a.compareTo(b) // return 1 (a>b)
a.equals(b)    // return false

List<Version> versions = new ArrayList<Version>();
versions.add(new Version("2"));
versions.add(new Version("1.0.5"));
versions.add(new Version("1.01.0"));
versions.add(new Version("1.00.1"));
Collections.min(versions).get() // return min version
Collections.max(versions).get() // return max version

// WARNING
Version a = new Version("2.06");
Version b = new Version("2.060");
a.equals(b)    // return false

Edit:

@daiscog: Terima kasih atas komentar Anda, kode ini telah dikembangkan untuk platform Android dan seperti yang direkomendasikan oleh Google, metode "cocok" memeriksa seluruh string seperti Java yang menggunakan pola pengaturan. ( Dokumentasi Android - Dokumentasi JAVA )


2
Ini adalah solusi IMHO terbaik. Saya membatasi ke 3 kode versi elemen dengan mengubahnya menjadi if (! Version.matches ("[0-9] + (\\. [0-9] +) {0,2}") dan dengan menambahkan variabel: private static final int [] PRIME = {2, 3, 5}; Saya bisa membuat kode hash yang hilang untuk yang di atas: @Override public int terakhir kode hash () {string terakhir [] bagian = this.get (). split ("\\."); int hashCode = 0; untuk (int i = 0; i <parts.length; i ++) {final int part = Integer.parseInt (bagian [i]); if (bagian> 0) { hashCode + = PRIME [i] ^ bagian;}} return hashCode;}
Barry Irvine

Anda setidaknya harus men-cache panggilan implisit Pattern.compile(), mengingat logika Anda dipanggil dengan O(N log N)kompleksitas.
Lukas Eder

implementasi ini menimpa sama dengan (Obyek itu) dan karena itu harus menimpa kode hash (). Dua objek yang sama harus mengembalikan kode hash yang sama jika tidak, Anda bisa mendapat masalah jika Anda menggunakan objek ini dengan koleksi hash.
Colin Phillips

Anda tidak dapat hash pada string versi karena 'Versi baru ("1.0"). Sama dengan (Versi baru ("1")' akan kembali benar. Ini akan berfungsi, tetapi tidak efisien ... // kontrak: setiap dua Versi yang sama harus mengembalikan kode hash yang sama. // karena "1.0" sama dengan "1", kita tidak bisa mengembalikan kode hash dari string versi. @Override public int hashCode () {return 1;}
Colin Phillips


106

Sangat mudah menggunakan Maven:

import org.apache.maven.artifact.versioning.DefaultArtifactVersion;

DefaultArtifactVersion minVersion = new DefaultArtifactVersion("1.0.1");
DefaultArtifactVersion maxVersion = new DefaultArtifactVersion("1.10");

DefaultArtifactVersion version = new DefaultArtifactVersion("1.11");

if (version.compareTo(minVersion) < 0 || version.compareTo(maxVersion) > 0) {
    System.out.println("Sorry, your version is unsupported");
}

Anda bisa mendapatkan string ketergantungan yang tepat untuk Maven Artifact dari halaman ini :

<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.0.3</version>
</dependency>

5
Saya telah menciptakan sebuah inti dengan tes tentang bagaimana hal ini dapat dilakukan: gist.github.com/2627608
yclian

11
Sempurna, jangan menemukan kembali rodanya!
Lluis Martinez

8
hanya satu kekuatiran adalah: untuk menggunakan ketergantungan ini dengan banyak file di dalamnya hanya untuk satu alasan - untuk memiliki satu kelas - DefaultArtifactVersion
ses

7
Penyimpanan @ses murah - tentu saja lebih murah daripada menulis, menguji dan memelihara kode asli
Alex Dean

11
Catatan yang Comparable.compareTodidokumentasikan sebagai mengembalikan "bilangan bulat negatif, nol, atau bilangan bulat positif", jadi itu kebiasaan yang baik untuk menghindari memeriksa -1 dan +1.
seanf

52

Anda perlu menormalkan string versi agar dapat dibandingkan. Sesuatu seperti

import java.util.regex.Pattern;

public class Main {
    public static void main(String... args) {
        compare("1.0", "1.1");
        compare("1.0.1", "1.1");
        compare("1.9", "1.10");
        compare("1.a", "1.9");
    }

    private static void compare(String v1, String v2) {
        String s1 = normalisedVersion(v1);
        String s2 = normalisedVersion(v2);
        int cmp = s1.compareTo(s2);
        String cmpStr = cmp < 0 ? "<" : cmp > 0 ? ">" : "==";
        System.out.printf("'%s' %s '%s'%n", v1, cmpStr, v2);
    }

    public static String normalisedVersion(String version) {
        return normalisedVersion(version, ".", 4);
    }

    public static String normalisedVersion(String version, String sep, int maxWidth) {
        String[] split = Pattern.compile(sep, Pattern.LITERAL).split(version);
        StringBuilder sb = new StringBuilder();
        for (String s : split) {
            sb.append(String.format("%" + maxWidth + 's', s));
        }
        return sb.toString();
    }
}

Cetakan

'1.0' < '1.1'
'1.0.1' < '1.1'
'1.9' < '1.10'
'1.a' > '1.9'

2
Peringatan untuk normalisasi adalah lebar maks tersirat yang Anda miliki di sana.
dlamblin

@IHeartAndroid Poin bagus, Kecuali jika Anda mengharapkan '4.1' == '4.1.0' Saya pikir ini adalah urutan pesan.
Peter Lawrey

lihat jawaban saya, saya telah menggeneralisasi jawabannya di sini
Abhinav Puri

48

Yang terbaik untuk menggunakan kembali kode yang ada, ambil kelas ComparableVersion Maven

keuntungan:

  • Lisensi Apache, Versi 2.0,
  • diuji,
  • digunakan (disalin) dalam beberapa proyek seperti pegas-keamanan-inti, JBoss dll
  • beberapa fitur
  • ini sudah menjadi java.lang.Comparable
  • cukup salin-tempel satu kelas itu, tanpa dependensi pihak ketiga

Jangan sertakan ketergantungan pada artefak pakar karena hal itu akan menarik berbagai ketergantungan transitif


Ini berbunyi seperti iklan dan tidak menambahkan apa pun ke jawaban lain.
eddie_cat

6
Ini relevan dengan pertanyaan seperti itu tentang metode standar untuk membandingkan versi dan perbandingan versi pakar cukup banyak standar.
Dileep

5
Ini jawaban terbaik. Saya tidak percaya berapa banyak orang lain (termasuk yang diterima) yang mencoba membelah string, tanpa tes. Contoh kode menggunakan kelas ini:assertTrue(new ComparableVersion("1.1-BETA").compareTo(new ComparableVersion("1.1-RC")) < 0)
Fabian Kessler

Kerugian: Menarik sejumlah dependensi, yang berarti sejumlah permukaan serangan dan potensi konflik versi.
toolforger

35
// VersionComparator.java
import java.util.Comparator;

public class VersionComparator implements Comparator {

    public boolean equals(Object o1, Object o2) {
        return compare(o1, o2) == 0;
    }

    public int compare(Object o1, Object o2) {
        String version1 = (String) o1;
        String version2 = (String) o2;

        VersionTokenizer tokenizer1 = new VersionTokenizer(version1);
        VersionTokenizer tokenizer2 = new VersionTokenizer(version2);

        int number1 = 0, number2 = 0;
        String suffix1 = "", suffix2 = "";

        while (tokenizer1.MoveNext()) {
            if (!tokenizer2.MoveNext()) {
                do {
                    number1 = tokenizer1.getNumber();
                    suffix1 = tokenizer1.getSuffix();
                    if (number1 != 0 || suffix1.length() != 0) {
                        // Version one is longer than number two, and non-zero
                        return 1;
                    }
                }
                while (tokenizer1.MoveNext());

                // Version one is longer than version two, but zero
                return 0;
            }

            number1 = tokenizer1.getNumber();
            suffix1 = tokenizer1.getSuffix();
            number2 = tokenizer2.getNumber();
            suffix2 = tokenizer2.getSuffix();

            if (number1 < number2) {
                // Number one is less than number two
                return -1;
            }
            if (number1 > number2) {
                // Number one is greater than number two
                return 1;
            }

            boolean empty1 = suffix1.length() == 0;
            boolean empty2 = suffix2.length() == 0;

            if (empty1 && empty2) continue; // No suffixes
            if (empty1) return 1; // First suffix is empty (1.2 > 1.2b)
            if (empty2) return -1; // Second suffix is empty (1.2a < 1.2)

            // Lexical comparison of suffixes
            int result = suffix1.compareTo(suffix2);
            if (result != 0) return result;

        }
        if (tokenizer2.MoveNext()) {
            do {
                number2 = tokenizer2.getNumber();
                suffix2 = tokenizer2.getSuffix();
                if (number2 != 0 || suffix2.length() != 0) {
                    // Version one is longer than version two, and non-zero
                    return -1;
                }
            }
            while (tokenizer2.MoveNext());

            // Version two is longer than version one, but zero
            return 0;
        }
        return 0;
    }
}

// VersionTokenizer.java
public class VersionTokenizer {
    private final String _versionString;
    private final int _length;

    private int _position;
    private int _number;
    private String _suffix;
    private boolean _hasValue;

    public int getNumber() {
        return _number;
    }

    public String getSuffix() {
        return _suffix;
    }

    public boolean hasValue() {
        return _hasValue;
    }

    public VersionTokenizer(String versionString) {
        if (versionString == null)
            throw new IllegalArgumentException("versionString is null");

        _versionString = versionString;
        _length = versionString.length();
    }

    public boolean MoveNext() {
        _number = 0;
        _suffix = "";
        _hasValue = false;

        // No more characters
        if (_position >= _length)
            return false;

        _hasValue = true;

        while (_position < _length) {
            char c = _versionString.charAt(_position);
            if (c < '0' || c > '9') break;
            _number = _number * 10 + (c - '0');
            _position++;
        }

        int suffixStart = _position;

        while (_position < _length) {
            char c = _versionString.charAt(_position);
            if (c == '.') break;
            _position++;
        }

        _suffix = _versionString.substring(suffixStart, _position);

        if (_position < _length) _position++;

        return true;
    }
}

Contoh:

public class Main
{
    private static VersionComparator cmp;

    public static void main (String[] args)
    {
        cmp = new VersionComparator();
        Test(new String[]{"1.1.2", "1.2", "1.2.0", "1.2.1", "1.12"});
        Test(new String[]{"1.3", "1.3a", "1.3b", "1.3-SNAPSHOT"});
    }

    private static void Test(String[] versions) {
        for (int i = 0; i < versions.length; i++) {
            for (int j = i; j < versions.length; j++) {
                Test(versions[i], versions[j]);
            }
        }
    }

    private static void Test(String v1, String v2) {
        int result = cmp.compare(v1, v2);
        String op = "==";
        if (result < 0) op = "<";
        if (result > 0) op = ">";
        System.out.printf("%s %s %s\n", v1, op, v2);
    }
}

Keluaran:

1.1.2 == 1.1.2                --->  same length and value
1.1.2 < 1.2                   --->  first number (1) less than second number (2) => -1
1.1.2 < 1.2.0                 --->  first number (1) less than second number (2) => -1
1.1.2 < 1.2.1                 --->  first number (1) less than second number (2) => -1
1.1.2 < 1.12                  --->  first number (1) less than second number (12) => -1
1.2 == 1.2                    --->  same length and value
1.2 == 1.2.0                  --->  first shorter than second, but zero
1.2 < 1.2.1                   --->  first shorter than second, and non-zero
1.2 < 1.12                    --->  first number (2) less than second number (12) => -1
1.2.0 == 1.2.0                --->  same length and value
1.2.0 < 1.2.1                 --->  first number (0) less than second number (1) => -1
1.2.0 < 1.12                  --->  first number (2) less than second number (12) => -1
1.2.1 == 1.2.1                --->  same length and value
1.2.1 < 1.12                  --->  first number (2) less than second number (12) => -1
1.12 == 1.12                  --->  same length and value

1.3 == 1.3                    --->  same length and value
1.3 > 1.3a                    --->  first suffix ('') is empty, but not second ('a') => 1
1.3 > 1.3b                    --->  first suffix ('') is empty, but not second ('b') => 1
1.3 > 1.3-SNAPSHOT            --->  first suffix ('') is empty, but not second ('-SNAPSHOT') => 1
1.3a == 1.3a                  --->  same length and value
1.3a < 1.3b                   --->  first suffix ('a') compared to second suffix ('b') => -1
1.3a < 1.3-SNAPSHOT           --->  first suffix ('a') compared to second suffix ('-SNAPSHOT') => -1
1.3b == 1.3b                  --->  same length and value
1.3b < 1.3-SNAPSHOT           --->  first suffix ('b') compared to second suffix ('-SNAPSHOT') => -1
1.3-SNAPSHOT == 1.3-SNAPSHOT  --->  same length and value

18

Bertanya-tanya mengapa semua orang menganggap bahwa versi hanya terdiri dari bilangan bulat - dalam kasus saya itu bukan.

Mengapa menciptakan kembali roda (dengan asumsi versi mengikuti standar Semver)

Pertama instal https://github.com/vdurmont/semver4j via Maven

Kemudian gunakan perpustakaan ini

Semver sem = new Semver("1.2.3");
sem.isGreaterThan("1.2.2"); // true

13
public static int compareVersions(String version1, String version2){

    String[] levels1 = version1.split("\\.");
    String[] levels2 = version2.split("\\.");

    int length = Math.max(levels1.length, levels2.length);
    for (int i = 0; i < length; i++){
        Integer v1 = i < levels1.length ? Integer.parseInt(levels1[i]) : 0;
        Integer v2 = i < levels2.length ? Integer.parseInt(levels2[i]) : 0;
        int compare = v1.compareTo(v2);
        if (compare != 0){
            return compare;
        }
    }

    return 0;
}

1
Berguna untuk kasus-kasus sederhana.
Christophe Roussy


4

Jika Anda sudah memiliki Jackson di proyek Anda, Anda dapat menggunakan com.fasterxml.jackson.core.Version:

import com.fasterxml.jackson.core.Version;
import org.junit.Test;

import static org.junit.Assert.assertTrue;

public class VersionTest {

    @Test
    public void shouldCompareVersion() {
        Version version1 = new Version(1, 11, 1, null, null, null);
        Version version2 = new Version(1, 12, 1, null, null, null);
        assertTrue(version1.compareTo(version2) < 0);
    }
}

2
public int compare(String v1, String v2) {
        v1 = v1.replaceAll("\\s", "");
        v2 = v2.replaceAll("\\s", "");
        String[] a1 = v1.split("\\.");
        String[] a2 = v2.split("\\.");
        List<String> l1 = Arrays.asList(a1);
        List<String> l2 = Arrays.asList(a2);


        int i=0;
        while(true){
            Double d1 = null;
            Double d2 = null;

            try{
                d1 = Double.parseDouble(l1.get(i));
            }catch(IndexOutOfBoundsException e){
            }

            try{
                d2 = Double.parseDouble(l2.get(i));
            }catch(IndexOutOfBoundsException e){
            }

            if (d1 != null && d2 != null) {
                if (d1.doubleValue() > d2.doubleValue()) {
                    return 1;
                } else if (d1.doubleValue() < d2.doubleValue()) {
                    return -1;
                }
            } else if (d2 == null && d1 != null) {
                if (d1.doubleValue() > 0) {
                    return 1;
                }
            } else if (d1 == null && d2 != null) {
                if (d2.doubleValue() > 0) {
                    return -1;
                }
            } else {
                break;
            }
            i++;
        }
        return 0;
    }

2
/**  
 *  written by: Stan Towianski - May 2018 
 * notes: I make assumption each of 3 version sections a.b.c is not longer then 4 digits: aaaa.bbbb.cccc-MODWORD1(-)modnum2
 * 5.10.13-release-1 becomes 0000500100013.501     6.0-snapshot becomes 0000600000000.100
 * MODWORD1 = -xyz/NotMatching, -SNAPSHOT, -ALPHA, -BETA, -RC, -RELEASE/nothing  return:  .0, .1, .2, .3, .4, .5
 * modnum2 = up to 2 digit/chars second version
 * */
public class VersionCk {

    private static boolean isVersionHigher( String baseVersion, String testVersion )
        {
        System.out.println( "versionToComparable( baseVersion ) =" + versionToComparable( baseVersion ) );
        System.out.println( "versionToComparable( testVersion ) =" + versionToComparable( testVersion ) + " is this higher ?" );
        return versionToComparable( testVersion ).compareTo( versionToComparable( baseVersion ) ) > 0;
        }

    //----  not worrying about += for something so small
    private static String versionToComparable( String version )
        {
//        System.out.println("version - " + version);
        String versionNum = version;
        int at = version.indexOf( '-' );
        if ( at >= 0 )
            versionNum = version.substring( 0, at );

        String[] numAr = versionNum.split( "\\." );
        String versionFormatted = "0";
        for ( String tmp : numAr )
            {
            versionFormatted += String.format( "%4s", tmp ).replace(' ', '0');
            }
        while ( versionFormatted.length() < 12 )  // pad out to aaaa.bbbb.cccc
            {
            versionFormatted += "0000";
            }
//        System.out.println( "converted min version =" + versionFormatted + "=   : " + versionNum );
        return versionFormatted + getVersionModifier( version, at );
        }

    //----  use order low to high: -xyz, -SNAPSHOT, -ALPHA, -BETA, -RC, -RELEASE/nothing  returns: 0, 1, 2, 3, 4, 5
    private static String getVersionModifier( String version, int at )
        {
//        System.out.println("version - " + version );
        String[] wordModsAr = { "-SNAPSHOT", "-ALPHA", "-BETA", "-RC", "-RELEASE" };        

        if ( at < 0 )
            return "." + wordModsAr.length + "00";   // make nothing = RELEASE level

        int i = 1;
        for ( String word : wordModsAr )
            {
            if ( ( at = version.toUpperCase().indexOf( word ) ) > 0 )
                return "." + i + getSecondVersionModifier( version.substring( at + word.length() ) );
            i++;
            }

        return ".000";
        }

    //----  add 2 chars for any number after first modifier.  -rc2 or -rc-2   returns 02
    private static String getSecondVersionModifier( String version )
        {
        System.out.println( "second modifier =" + version + "=" );
        Matcher m = Pattern.compile("(.*?)(\\d+).*").matcher( version );
//        if ( m.matches() )
//            System.out.println( "match ? =" + m.matches() + "=   m.group(1) =" + m.group(1) + "=   m.group(2) =" + m.group(2) + "=   m.group(3) =" + (m.groupCount() >= 3 ? m.group(3) : "x") );
//        else
//            System.out.println( "No match" );
        return m.matches() ? String.format( "%2s", m.group(2) ).replace(' ', '0') : "00";
        }

    public static void main(String[] args) 
        {
        checkVersion( "3.10.0", "3.4.0");
        checkVersion( "5.4.2", "5.4.1");
        checkVersion( "5.4.4", "5.4.5");
        checkVersion( "5.4.9", "5.4.12");
        checkVersion( "5.9.222", "5.10.12");
        checkVersion( "5.10.12", "5.10.12");
        checkVersion( "5.10.13", "5.10.14");
        checkVersion( "6.7.0", "6.8");
        checkVersion( "6.7", "2.7.0");
        checkVersion( "6", "6.3.1");
        checkVersion( "4", "4.0.0");
        checkVersion( "6.3.0", "6");
        checkVersion( "5.10.12-Alpha", "5.10.12-beTA");
        checkVersion( "5.10.13-release", "5.10.14-beta");
        checkVersion( "6.7.0", "6.8-snapshot");
        checkVersion( "6.7.1", "6.7.0-release");
        checkVersion( "6-snapshot", "6.0.0-beta");
        checkVersion( "6.0-snapshot", "6.0.0-whatthe");
        checkVersion( "5.10.12-Alpha-1", "5.10.12-alpha-2");
        checkVersion( "5.10.13-release-1", "5.10.13-release2");
        checkVersion( "10-rc42", "10.0.0-rc53");
        }

    private static void checkVersion(String baseVersion, String testVersion) 
        {
        System.out.println( "baseVersion - " + baseVersion );
        System.out.println( "testVersion - " + testVersion );
        System.out.println( "isVersionHigher = " + isVersionHigher( baseVersion, testVersion ) );
        System.out.println( "---------------");
        }

    }

beberapa output:

---------------
baseVersion - 6.7
testVersion - 2.7.0
versionToComparable( baseVersion ) =0000600070000.500
versionToComparable( testVersion ) =0000200070000.500 is this higher ?
isVersionHigher = false
---------------
baseVersion - 6
testVersion - 6.3.1
versionToComparable( baseVersion ) =0000600000000.500
versionToComparable( testVersion ) =0000600030001.500 is this higher ?
isVersionHigher = true
---------------
baseVersion - 4
testVersion - 4.0.0
versionToComparable( baseVersion ) =0000400000000.500
versionToComparable( testVersion ) =0000400000000.500 is this higher ?
isVersionHigher = false
---------------
baseVersion - 6.3.0
testVersion - 6
versionToComparable( baseVersion ) =0000600030000.500
versionToComparable( testVersion ) =0000600000000.500 is this higher ?
isVersionHigher = false
---------------
baseVersion - 5.10.12-Alpha
testVersion - 5.10.12-beTA
second modifier ==
versionToComparable( baseVersion ) =0000500100012.200
second modifier ==
versionToComparable( testVersion ) =0000500100012.300 is this higher ?
second modifier ==
second modifier ==
isVersionHigher = true
---------------
baseVersion - 5.10.13-release
testVersion - 5.10.14-beta
second modifier ==
versionToComparable( baseVersion ) =0000500100013.500
second modifier ==
versionToComparable( testVersion ) =0000500100014.300 is this higher ?
second modifier ==
second modifier ==
isVersionHigher = true
---------------
baseVersion - 6.7.0
testVersion - 6.8-snapshot
versionToComparable( baseVersion ) =0000600070000.500
second modifier ==
versionToComparable( testVersion ) =0000600080000.100 is this higher ?
second modifier ==
isVersionHigher = true
---------------
baseVersion - 6.7.1
testVersion - 6.7.0-release
versionToComparable( baseVersion ) =0000600070001.500
second modifier ==
versionToComparable( testVersion ) =0000600070000.500 is this higher ?
second modifier ==
isVersionHigher = false
---------------
baseVersion - 6-snapshot
testVersion - 6.0.0-beta
second modifier ==
versionToComparable( baseVersion ) =0000600000000.100
second modifier ==
versionToComparable( testVersion ) =0000600000000.300 is this higher ?
second modifier ==
second modifier ==
isVersionHigher = true
---------------
baseVersion - 6.0-snapshot
testVersion - 6.0.0-whatthe
second modifier ==
versionToComparable( baseVersion ) =0000600000000.100
versionToComparable( testVersion ) =0000600000000.000 is this higher ?
second modifier ==
isVersionHigher = false
---------------
baseVersion - 5.10.12-Alpha-1
testVersion - 5.10.12-alpha-2
second modifier =-1=
versionToComparable( baseVersion ) =0000500100012.201
second modifier =-2=
versionToComparable( testVersion ) =0000500100012.202 is this higher ?
second modifier =-2=
second modifier =-1=
isVersionHigher = true
---------------
baseVersion - 5.10.13-release-1
testVersion - 5.10.13-release2
second modifier =-1=
versionToComparable( baseVersion ) =0000500100013.501
second modifier =2=
versionToComparable( testVersion ) =0000500100013.502 is this higher ?
second modifier =2=
second modifier =-1=
isVersionHigher = true
---------------
baseVersion - 10-rc42
testVersion - 10.0.0-rc53
second modifier =42=
versionToComparable( baseVersion ) =0001000000000.442
second modifier =53=
versionToComparable( testVersion ) =0001000000000.453 is this higher ?
second modifier =53=
second modifier =42=
isVersionHigher = true
---------------

2

Saya menulis Perpustakaan Open Source bernama MgntUtils yang memiliki utilitas yang berfungsi dengan versi String. Itu benar membandingkan mereka, bekerja dengan rentang versi dan sebagainya. Berikut ini adalah pustaka metode javadoc See TextUtils.comapreVersions(...). Telah banyak digunakan dan diuji dengan baik. Berikut adalah artikel yang menjelaskan tentang perpustakaan dan di mana mendapatkannya. Ini tersedia sebagai artefak Maven dan pada github (dengan sumber dan JavaDoc)


1

untuk proyek-proyek saya, saya menggunakan pustaka versi-milik umum saya https://github.com/raydac/commons-version yang berisi dua kelas tambahan - untuk mem-parsing versi (parsing versi dapat dibandingkan dengan objek versi lain karena ia sebanding) dan VersionValidator yang memungkinkan untuk memeriksa versi untuk beberapa ekspresi seperti!=ide-1.1.1,>idea-1.3.4-SNAPSHOT;<1.2.3


1

Saya membuat utilitas sederhana untuk membandingkan versi pada platform Android menggunakan konvensi Semantic Versioning . Jadi itu hanya berfungsi untuk string dalam format XYZ (Major.Minor.Patch) di mana X, Y, dan Z adalah bilangan bulat non-negatif. Anda dapat menemukannya di GitHub saya .

Metode Version.compareVersions (String v1, String v2) membandingkan dua string versi. Ini mengembalikan 0 jika versinya sama, 1 jika versi v1 sebelum versi v2, -1 jika versi v1 setelah versi v2, -2 jika format versi tidak valid.


tautan GitHub Anda tidak ditemukan
aldok

1
public int CompareVersions(String version1, String version2)
{
    String[] string1Vals = version1.split("\\.");
    String[] string2Vals = version2.split("\\.");

    int length = Math.max(string1Vals.length, string2Vals.length);

    for (int i = 0; i < length; i++)
    {
        Integer v1 = (i < string1Vals.length)?Integer.parseInt(string1Vals[i]):0;
        Integer v2 = (i < string2Vals.length)?Integer.parseInt(string2Vals[i]):0;

        //Making sure Version1 bigger than version2
        if (v1 > v2)
        {
            return 1;
        }
        //Making sure Version1 smaller than version2
        else if(v1 < v2)
        {
            return -1;
        }
    }

    //Both are equal
    return 0;
}

1

@ Posting alex di Kotlin

class Version(inputVersion: String) : Comparable<Version> {

        var version: String
            private set

        override fun compareTo(other: Version) =
            (split() to other.split()).let {(thisParts, thatParts)->
                val length = max(thisParts.size, thatParts.size)
                for (i in 0 until length) {
                    val thisPart = if (i < thisParts.size) thisParts[i].toInt() else 0
                    val thatPart = if (i < thatParts.size) thatParts[i].toInt() else 0
                    if (thisPart < thatPart) return -1
                    if (thisPart > thatPart) return 1
                }
                 0
            }

        init {
            require(inputVersion.matches("[0-9]+(\\.[0-9]+)*".toRegex())) { "Invalid version format" }
            version = inputVersion
        }
    }

    fun Version.split() = version.split(".").toTypedArray()

pemakaian:

Version("1.2.4").compareTo(Version("0.0.5")) //return 1

0

Menulis sedikit fungsi sendiri. Lebih Sederhana Menggunakan Daftar

 public static boolean checkVersionUpdate(String olderVerison, String newVersion) {
        if (olderVerison.length() == 0 || newVersion.length() == 0) {
            return false;
        }
        List<String> newVerList = Arrays.asList(newVersion.split("\\."));
        List<String> oldVerList = Arrays.asList(olderVerison.split("\\."));

        int diff = newVerList.size() - oldVerList.size();
        List<String> newList = new ArrayList<>();
        if (diff > 0) {
            newList.addAll(oldVerList);
            for (int i = 0; i < diff; i++) {
                newList.add("0");
            }
            return examineArray(newList, newVerList, diff);
        } else if (diff < 0) {
            newList.addAll(newVerList);
            for (int i = 0; i < -diff; i++) {
                newList.add("0");
            }
            return examineArray(oldVerList, newList, diff);
        } else {
            return examineArray(oldVerList, newVerList, diff);
        }

    }

    public static boolean examineArray(List<String> oldList, List<String> newList, int diff) {
        boolean newVersionGreater = false;
        for (int i = 0; i < oldList.size(); i++) {
            if (Integer.parseInt(newList.get(i)) > Integer.parseInt(oldList.get(i))) {
                newVersionGreater = true;
                break;
            } else if (Integer.parseInt(newList.get(i)) < Integer.parseInt(oldList.get(i))) {
                newVersionGreater = false;
                break;
            } else {
                newVersionGreater = diff > 0;
            }
        }

        return newVersionGreater;
    }

0

Saya telah menulis perpustakaan kecil Java / Android untuk membandingkan nomor versi: https://github.com/G00fY2/version-compare

Apa yang pada dasarnya dilakukannya adalah ini:

  public int compareVersions(String versionA, String versionB) {
    String[] versionTokensA = versionA.split("\\.");
    String[] versionTokensB = versionB.split("\\.");
    List<Integer> versionNumbersA = new ArrayList<>();
    List<Integer> versionNumbersB = new ArrayList<>();

    for (String versionToken : versionTokensA) {
      versionNumbersA.add(Integer.parseInt(versionToken));
    }
    for (String versionToken : versionTokensB) {
      versionNumbersB.add(Integer.parseInt(versionToken));
    }

    final int versionASize = versionNumbersA.size();
    final int versionBSize = versionNumbersB.size();
    int maxSize = Math.max(versionASize, versionBSize);

    for (int i = 0; i < maxSize; i++) {
      if ((i < versionASize ? versionNumbersA.get(i) : 0) > (i < versionBSize ? versionNumbersB.get(i) : 0)) {
        return 1;
      } else if ((i < versionASize ? versionNumbersA.get(i) : 0) < (i < versionBSize ? versionNumbersB.get(i) : 0)) {
        return -1;
      }
    }
    return 0;
  }

Cuplikan ini tidak menawarkan pemeriksaan atau penanganan kesalahan. Selain itu perpustakaan saya juga mendukung sufiks seperti "1.2-rc"> "1.2-beta".


0

Menggunakan Java 8 Stream untuk mengganti nol terkemuka di komponen. Kode ini lulus semua tes di interviewbit.com

public int compareVersion(String A, String B) {
    List<String> strList1 = Arrays.stream(A.split("\\."))
                                           .map(s -> s.replaceAll("^0+(?!$)", ""))
                                           .collect(Collectors.toList());
    List<String> strList2 = Arrays.stream(B.split("\\."))
                                           .map(s -> s.replaceAll("^0+(?!$)", ""))
                                           .collect(Collectors.toList());
    int len1 = strList1.size();
    int len2 = strList2.size();
    int i = 0;
    while(i < len1 && i < len2){
        if (strList1.get(i).length() > strList2.get(i).length()) return 1;
        if (strList1.get(i).length() < strList2.get(i).length()) return -1;
        int result = new Long(strList1.get(i)).compareTo(new Long(strList2.get(i)));
        if (result != 0) return result;
        i++;
    }
    while (i < len1){
        if (!strList1.get(i++).equals("0")) return 1;
    }
    while (i < len2){
        if (!strList2.get(i++).equals("0")) return -1;
    }
    return 0;
}

0

Karena tidak ada jawaban di halaman ini yang menangani teks campuran dengan baik, saya membuat versi saya sendiri:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Main {
    static double parseVersion(String v) {
        if (v.isEmpty()) {
            return 0;
        }
        Pattern p = Pattern.compile("^(\\D*)(\\d*)(\\D*)$");
        Matcher m = p.matcher(v);
    m.find();
    if (m.group(2).isEmpty()) {
      // v1.0.0.[preview]
      return -1;
    }
        double i = Integer.parseInt(m.group(2));
    if (!m.group(3).isEmpty()) {
      // v1.0.[0b]
      i -= 0.1;
    }
    return i;
    }

    public static int versionCompare(String str1, String str2) {
        String[] v1 = str1.split("\\.");
        String[] v2 = str2.split("\\.");
        int i = 0;
        for (; i < v1.length && i < v2.length; i++) {
            double iv1 = parseVersion(v1[i]);
            double iv2 = parseVersion(v2[i]);

            if (iv1 != iv2) {
                return iv1 - iv2 < 0 ? -1 : 1;
            }
        }
        if (i < v1.length) {
      // "1.0.1", "1.0"
            double iv1 = parseVersion(v1[i]);
            return iv1 < 0 ? -1 : (int)Math.ceil(iv1);
        }
        if (i < v2.length) {
            double iv2 = parseVersion(v2[i]);
            return - iv2 < 0 ? -1 : (int)Math.ceil(iv2);
        }
        return 0;
    }


  public static void main(String[] args) {
    System.out.println("versionCompare(v1.0.0, 1.0.0)");
    System.out.println(versionCompare("v1.0.0", "1.0.0")); // 0

    System.out.println("versionCompare(v1.0.0b, 1.0.0)");
    System.out.println(versionCompare("v1.0.0b", "1.0.0")); // -1

    System.out.println("versionCompare(v1.0.0.preview, 1.0.0)");
    System.out.println(versionCompare("v1.0.0.preview", "1.0.0")); // -1

    System.out.println("versionCompare(v1.0, 1.0.0)");
    System.out.println(versionCompare("v1.0", "1.0.0")); // 0

    System.out.println("versionCompare(ver1.0, 1.0.1)");
    System.out.println(versionCompare("ver1.0", "1.0.1")); // -1
  }
}

Itu masih gagal pada kasus-kasus di mana Anda perlu membandingkan "alpha" dengan "beta" sekalipun.


0

Untuk seseorang yang akan menampilkan Alert Pembaruan Angkatan berdasarkan nomor versi saya punya Ide berikut. Ini dapat digunakan ketika membandingkan versi antara versi Aplikasi Android Saat Ini dan versi konfigurasi jarak jauh firebase. Ini bukan jawaban untuk pertanyaan yang diajukan tetapi ini akan membantu seseorang dengan pasti.

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
public class Main
{
  static String firebaseVersion = "2.1.3"; // or 2.1
  static String appVersion = "2.1.4";
  static List<String> firebaseVersionArray;
  static List<String> appVersionArray;
  static boolean isNeedToShowAlert = false;
  public static void main (String[]args)
  {
    System.out.println ("Hello World");
    firebaseVersionArray = new ArrayList<String>(Arrays.asList(firebaseVersion.split ("\\.")));
    appVersionArray = new ArrayList<String>(Arrays.asList(appVersion.split ("\\.")));
    if(appVersionArray.size() < firebaseVersionArray.size()) {
        appVersionArray.add("0");
    }
    if(firebaseVersionArray.size() < appVersionArray.size()) {
        firebaseVersionArray.add("0");
    }
    isNeedToShowAlert = needToShowAlert(); //Returns false
    System.out.println (isNeedToShowAlert);

  }
  static boolean needToShowAlert() {
      boolean result = false;
      for(int i = 0 ; i < appVersionArray.size() ; i++) {
          if (Integer.parseInt(appVersionArray.get(i)) == Integer.parseInt(firebaseVersionArray.get(i))) {
              continue;
          } else if (Integer.parseInt(appVersionArray.get(i)) > Integer.parseInt(firebaseVersionArray.get(i))){
             result = false;
             break;
          } else if (Integer.parseInt(appVersionArray.get(i)) < Integer.parseInt(firebaseVersionArray.get(i))) {
             result = true;
             break;  
          }
      }
      return result;
  }
}

Anda dapat menjalankan kode ini dengan menyalin paste di https://www.onlinegdb.com/online_java_compiler


0
public static void main(String[] args) {

    String version1 = "1.0";
    String version2 = "1.0.0";
    String[] version1_splits = version1.split("\\.");
    String[] version2_splits = version2.split("\\.");
    int length = version1_splits.length >= version2_splits.length ? version1_splits.length : version2_splits.length;
    int i=0;
    for(;i<length;i++){
        int version1_int = getValue(version1_splits,i);
        int version2_int = getValue(version2_splits,i);
        if(version1_int > version2_int){
            System.out.println("version1 > version2");
            break;
        }
        else if(version1_int < version2_int){
            System.out.println("version2 > version1");
            break;
        }
        else{
            if(i == length-1)
            System.out.println("version1 = version2");
        }
    }
}

private static int getValue(String[] version1_splits, int i) {
    int temp;
    try{
        temp = Integer.valueOf(version1_splits[i]);
    }
    catch(IndexOutOfBoundsException e){
        temp=0;
    }

    return temp;
}

0

Saya melakukannya sekarang dan bertanya pada diri sendiri, apakah itu benar? Karena saya belum pernah menemukan solusi terbersih sebelumnya daripada solusi saya:

Anda hanya perlu membagi versi string ("1.0.0") seperti contoh ini:

userVersion.split("\\.")

Maka Anda akan memiliki: {"1", "0", "0"}

Sekarang, menggunakan metode yang saya lakukan:

isUpdateAvailable(userVersion.split("\\."), latestVersionSplit.split("\\."));

Metode:

/**
 * Compare two versions
 *
 * @param userVersionSplit   - User string array with major, minor and patch version from user (exemple: {"5", "2", "70"})
 * @param latestVersionSplit - Latest string array with major, minor and patch version from api (example: {"5", "2", "71"})
 * @return true if user version is smaller than latest version
 */
public static boolean isUpdateAvailable(String[] userVersionSplit, String[] latestVersionSplit) {

    int majorUserVersion = Integer.parseInt(userVersionSplit[0]);
    int minorUserVersion = Integer.parseInt(userVersionSplit[1]);
    int patchUserVersion = Integer.parseInt(userVersionSplit[2]);

    int majorLatestVersion = Integer.parseInt(latestVersionSplit[0]);
    int minorLatestVersion = Integer.parseInt(latestVersionSplit[1]);
    int patchLatestVersion = Integer.parseInt(latestVersionSplit[2]);

    if (majorUserVersion <= majorLatestVersion) {
        if (majorUserVersion < majorLatestVersion) {
            return true;
        } else {
            if (minorUserVersion <= minorLatestVersion) {
                if (minorUserVersion < minorLatestVersion) {
                    return true;
                } else {
                    return patchUserVersion < patchLatestVersion;
                }
            }
        }
    }

    return false;
}

Menunggu umpan balik :)


0

berdasarkan https://stackoverflow.com/a/27891752/2642478

class Version(private val value: String) : Comparable<Version> {
    private val splitted by lazy { value.split("-").first().split(".").map { it.toIntOrNull() ?: 0 } }

    override fun compareTo(other: Version): Int {
        for (i in 0 until maxOf(splitted.size, other.splitted.size)) {
            val compare = splitted.getOrElse(i) { 0 }.compareTo(other.splitted.getOrElse(i) { 0 })
            if (compare != 0)
                return compare
        }
        return 0
    }
}

Anda dapat menggunakan seperti:

    System.err.println(Version("1.0").compareTo( Version("1.0")))
    System.err.println(Version("1.0") < Version("1.1"))
    System.err.println(Version("1.10") > Version("1.9"))
    System.err.println(Version("1.10.1") > Version("1.10"))
    System.err.println(Version("0.0.1") < Version("1"))

-1

Kode ini mencoba menyelesaikan jenis versi perbandingan ini.

Sebagian besar penentu versi, seperti> = 1.0, cukup jelas. Specifier ~> memiliki arti khusus, paling baik ditunjukkan dengan contoh. ~> 2.0.3 identik dengan> = 2.0.3 dan <2.1. ~> 2.1 identik dengan> = 2.1 dan <3.0.

public static boolean apply(String cmpDeviceVersion, String reqDeviceVersion)
{
    Boolean equal           = !cmpDeviceVersion.contains(">") && !cmpDeviceVersion.contains(">=") &&
                              !cmpDeviceVersion.contains("<") && !cmpDeviceVersion.contains("<=") &&
                              !cmpDeviceVersion.contains("~>");

    Boolean between         = cmpDeviceVersion.contains("~>");
    Boolean higher          = cmpDeviceVersion.contains(">") && !cmpDeviceVersion.contains(">=") && !cmpDeviceVersion.contains("~>");
    Boolean higherOrEqual   = cmpDeviceVersion.contains(">=");

    Boolean less            = cmpDeviceVersion.contains("<") && !cmpDeviceVersion.contains("<=");
    Boolean lessOrEqual     = cmpDeviceVersion.contains("<=");

    cmpDeviceVersion        = cmpDeviceVersion.replaceAll("[<>=~]", "");
    cmpDeviceVersion        = cmpDeviceVersion.trim();

    String[] version        = cmpDeviceVersion.split("\\.");
    String[] reqVersion     = reqDeviceVersion.split("\\.");

    if(equal)
    {
        return isEqual(version, reqVersion);
    }
    else if(between)
    {
        return isBetween(version, reqVersion);
    }
    else if(higher)
    {
        return isHigher(version, reqVersion);
    }
    else if(higherOrEqual)
    {
        return isEqual(version, reqVersion) || isHigher(version, reqVersion);
    }
    else if(less)
    {
        return isLess(version, reqVersion);
    }
    else if(lessOrEqual)
    {
        return isEqual(version, reqVersion) || isLess(version, reqVersion);
    }

    return false;
}

private static boolean isEqual(String[] version, String[] reqVersion)
{
    String strVersion = StringUtils.join(version);
    String strReqVersion = StringUtils.join(reqVersion);
    if(version.length > reqVersion.length)
    {
        Integer diff = version.length - reqVersion.length;
        strReqVersion += StringUtils.repeat(".0", diff);
    }
    else if(reqVersion.length > version.length)
    {
        Integer diff = reqVersion.length - version.length;
        strVersion += StringUtils.repeat(".0", diff);
    }

    return strVersion.equals(strReqVersion);
}

private static boolean isHigher(String[] version, String[] reqVersion)
{
    String strVersion = StringUtils.join(version);
    String strReqVersion = StringUtils.join(reqVersion);
    if(version.length > reqVersion.length)
    {
        Integer diff = version.length - reqVersion.length;
        strReqVersion += StringUtils.repeat(".0", diff);
    }
    else if(reqVersion.length > version.length)
    {
        Integer diff = reqVersion.length - version.length;
        strVersion += StringUtils.repeat(".0", diff);
    }

    return strReqVersion.compareTo(strVersion) > 0;
}

private static boolean isLess(String[] version, String[] reqVersion)
{
    String strVersion = StringUtils.join(version);
    String strReqVersion = StringUtils.join(reqVersion);
    if(version.length > reqVersion.length)
    {
        Integer diff = version.length - reqVersion.length;
        strReqVersion += StringUtils.repeat(".0", diff);
    }
    else if(reqVersion.length > version.length)
    {
        Integer diff = reqVersion.length - version.length;
        strVersion += StringUtils.repeat(".0", diff);
    }

    return strReqVersion.compareTo(strVersion) < 0;
}

private static boolean isBetween(String[] version, String[] reqVersion)
{
    return (isEqual(version, reqVersion) || isHigher(version, reqVersion)) &&
            isLess(getNextVersion(version), reqVersion);
}

private static String[] getNextVersion(String[] version)
{
    String[] nextVersion = new String[version.length];
    for(int i = version.length - 1; i >= 0 ; i--)
    {
        if(i == version.length - 1)
        {
            nextVersion[i] = "0";
        }
        else if((i == version.length - 2) && NumberUtils.isNumber(version[i]))
        {
            nextVersion[i] = String.valueOf(NumberUtils.toInt(version[i]) + 1);
        }
        else
        {
            nextVersion[i] = version[i];
        }
    }
    return nextVersion;
}

-1

Saya menyukai ide dari @Peter Lawrey, dan saya memperluasnya ke batas lebih lanjut:

    /**
    * Normalize string array, 
    * Appends zeros if string from the array
    * has length smaller than the maxLen.
    **/
    private String normalize(String[] split, int maxLen){
        StringBuilder sb = new StringBuilder("");
        for(String s : split) {
            for(int i = 0; i<maxLen-s.length(); i++) sb.append('0');
            sb.append(s);
        }
        return sb.toString();
    }

    /**
    * Removes trailing zeros of the form '.00.0...00'
    * (and does not remove zeros from, say, '4.1.100')
    **/
    public String removeTrailingZeros(String s){
        int i = s.length()-1;
        int k = s.length()-1;
        while(i >= 0 && (s.charAt(i) == '.' || s.charAt(i) == '0')){
          if(s.charAt(i) == '.') k = i-1;
          i--;  
        } 
        return s.substring(0,k+1);
    }

    /**
    * Compares two versions(works for alphabets too),
    * Returns 1 if v1 > v2, returns 0 if v1 == v2,
    * and returns -1 if v1 < v2.
    **/
    public int compareVersion(String v1, String v2) {

        // Uncomment below two lines if for you, say, 4.1.0 is equal to 4.1
        // v1 = removeTrailingZeros(v1);
        // v2 = removeTrailingZeros(v2);

        String[] splitv1 = v1.split("\\.");
        String[] splitv2 = v2.split("\\.");
        int maxLen = 0;
        for(String str : splitv1) maxLen = Math.max(maxLen, str.length());
        for(String str : splitv2) maxLen = Math.max(maxLen, str.length());
        int cmp = normalize(splitv1, maxLen).compareTo(normalize(splitv2, maxLen));
        return cmp > 0 ? 1 : (cmp < 0 ? -1 : 0);
    }

Semoga ini bisa membantu seseorang. Itu melewati semua kasus uji dalam interviewbit dan leetcode (perlu batalkan komentar dua baris dalam fungsi compareVersion).

Mudah diuji!


-2
public class VersionComparator {

    /* loop through both version strings
     * then loop through the inner string to computer the val of the int
     * for each integer read, do num*10+<integer read>
     * and stop when stumbling upon '.'
     * When '.' is encountered...
     * see if '.' is encountered for both strings
     * if it is then compare num1 and num2 
     * if num1 == num2... iterate over p1++, p2++
     * else return (num1 > num2) ? 1 : -1
     * If both the string end then compare(num1, num2) return 0, 1, -1
     * else loop through the longer string and 
     * verify if it only has trailing zeros
     * If it only has trailing zeros then return 0
     * else it is greater than the other string
     */
    public static int compareVersions(String v1, String v2) {
        int num1 = 0;
        int num2 = 0;
        int p1 = 0;
        int p2 = 0;

        while (p1 < v1.length() && p2 < v2.length()) {
            num1 = Integer.parseInt(v1.charAt(p1) + "");
            num2 = Integer.parseInt(v2.charAt(p2) + "");
            p1++;
            p2++;

            while (p1 < v1.length() && p2 < v2.length() && v1.charAt(p1) != '.' && v2.charAt(p2) != '.') {
                if (p1 < v1.length()) num1 = num1 * 10 + Integer.parseInt(v1.charAt(p1) + "");
                if (p2 < v2.length()) num2 = num2 * 10 + Integer.parseInt(v2.charAt(p2) + "");
                p1++;
                p2++;
            }

            if (p1 < v1.length() && p2 < v2.length() && v1.charAt(p1) == '.' && v2.charAt(p2) == '.') {
                if ((num1 ^ num2) == 0) {
                    p1++;
                    p2++;
                }
                else return (num1 > num2) ? 1 : -1;
            }
            else if (p1 < v1.length() && p2 < v2.length() && v1.charAt(p1) == '.') return -1;
            else if (p1 < v1.length() && p2 < v2.length() && v2.charAt(p2) == '.') return 1;
        }

        if (p1 == v1.length() && p2 == v2.length()) {
            if ((num1 ^ num2) == 0) return 0;
            else return (num1 > num2) ? 1 : -1;
        }
        else if (p1 == v1.length()) {
            if ((num1 ^ num2) == 0) {
                while (p2 < v2.length()) {
                    if (v2.charAt(p2) != '.' && v2.charAt(p2) != '0') return -1;
                    p2++;
                }
                return 0;
            }
            else return (num1 > num2) ? 1 : -1;
        }
        else {
            if ((num1 ^ num2) == 0) {
                while (p1 < v1.length()) {
                    if (v1.charAt(p1) != '.' && v1.charAt(p1) != '0') return 1;
                    p1++;
                }
                return 0;
            }
            else return (num1 > num2) ? 1 : -1;
        }
    }

    public static void main(String[] args) {
        System.out.println(compareVersions("11.23", "11.21.1.0.0.1.0") ^ 1);
        System.out.println(compareVersions("11.21.1.0.0.1.0", "11.23") ^ -1);
        System.out.println(compareVersions("11.23", "11.23.0.0.0.1.0") ^ -1);
        System.out.println(compareVersions("11.2", "11.23") ^ -1);
        System.out.println(compareVersions("11.23", "11.21.1.0.0.1.0") ^ 1);
        System.out.println(compareVersions("1.21.1.0.0.1.0", "2.23") ^ -1);
        System.out.println(compareVersions("11.23", "11.21.1.0.0.1.0") ^ 1);
        System.out.println(compareVersions("11.23.0.0.0.0.0", "11.23") ^ 0);
        System.out.println(compareVersions("11.23", "11.21.1.0.0.1.0") ^ 1);
        System.out.println(compareVersions("1.5.1.3", "1.5.1.3.0") ^ 0);
        System.out.println(compareVersions("1.5.1.4", "1.5.1.3.0") ^ 1);
        System.out.println(compareVersions("1.2.1.3", "1.5.1.3.0") ^ -1);
        System.out.println(compareVersions("1.2.1.3", "1.22.1.3.0") ^ -1);
        System.out.println(compareVersions("1.222.1.3", "1.22.1.3.0") ^ 1);
    }
}

-2

Inilah implementasi yang dioptimalkan:

public static final Comparator<CharSequence> VERSION_ORDER = new Comparator<CharSequence>() {

  @Override
  public int compare (CharSequence lhs, CharSequence rhs) {
    int ll = lhs.length(), rl = rhs.length(), lv = 0, rv = 0, li = 0, ri = 0;
    char c;
    do {
      lv = rv = 0;
      while (--ll >= 0) {
        c = lhs.charAt(li++);
        if (c < '0' || c > '9')
          break;
        lv = lv*10 + c - '0';
      }
      while (--rl >= 0) {
        c = rhs.charAt(ri++);
        if (c < '0' || c > '9')
          break;
        rv = rv*10 + c - '0';
      }
    } while (lv == rv && (ll >= 0 || rl >= 0));
    return lv - rv;
  }

};

Hasil:

"0.1" - "1.0" = -1
"1.0" - "1.0" = 0
"1.0" - "1.0.0" = 0
"10" - "1.0" = 9
"3.7.6" - "3.7.11" = -5
"foobar" - "1.0" = -1
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.