[Javascript] どのようにjsを使用してソフトウェアのバージョン番号を比較する? (数字のみ)


Answers

// Return 1 if a > b
// Return -1 if a < b
// Return 0 if a == b
function compare(a, b) {
    if (a === b) {
       return 0;
    }

    var a_components = a.split(".");
    var b_components = b.split(".");

    var len = Math.min(a_components.length, b_components.length);

    // loop while the components are equal
    for (var i = 0; i < len; i++) {
        // A bigger than B
        if (parseInt(a_components[i]) > parseInt(b_components[i])) {
            return 1;
        }

        // B bigger than A
        if (parseInt(a_components[i]) < parseInt(b_components[i])) {
            return -1;
        }
    }

    // If one's a prefix of the other, the longer one is greater.
    if (a_components.length > b_components.length) {
        return 1;
    }

    if (a_components.length < b_components.length) {
        return -1;
    }

    // Otherwise they are the same.
    return 0;
}

console.log(compare("1", "2"));
console.log(compare("2", "1"));

console.log(compare("1.0", "1.0"));
console.log(compare("2.0", "1.0"));
console.log(compare("1.0", "2.0"));
console.log(compare("1.0.1", "1.0"));
Question

ソフトウェアのバージョン番号は次のとおりです。

"1.0", "1.0.1", "2.0", "2.0.0.1", "2.0.1"

どうすればこれを比較できますか? 正しい順序は次のとおりとします。

"1.0", "1.0.1", "2.0", "2.0.0.1", "2.0.1"

アイデアは簡単です...:最初の桁を読んで、2番目の桁を3番目の桁の後に読みます。しかし、バージョン番号をフロート番号に変換することはできません....また、次のようなバージョン番号を見ることができますこの:

"1.0.0.0", "1.0.1.0", "2.0.0.0", "2.0.0.1", "2.0.1.0"

そして、これは背後にあるアイディアが何であるかを見るのがはっきりしています...しかし、それをコンピュータープログラムに変換する方法は? どのようにこれを並べ替えるかについての任意のアイデアを持っていますか? ありがとうございました。




replace()関数は、文字列内の最初の出現箇所のみを置き換えます。 だから、それを置き換えることができます., 。 その後、すべてを削除します. そして, 〜にする. 再び浮動小数点数を解析します。

for(i=0; i<versions.length; i++) {
    v = versions[i].replace('.', ',');
    v = v.replace(/\./g, '');
    versions[i] = parseFloat(v.replace(',', '.'));
}

最後に、ソートしてください:

versions.sort();



これはきちんとしたトリックです。 特定の値の範囲の数値を扱う場合は、バージョンオブジェクトの各レベルに値を割り当てることができます。 たとえば、 "largestValue"はここで0xFFに設定されています。これはあなたのバージョン管理に対して非常に "IP"な外観を作り出します。

これは、アルファベットのバージョニング(1.2a <1.2b)

// The version compare function
function compareVersion(data0, data1, levels) {
    function getVersionHash(version) {
        var value = 0;
        version = version.split(".").map(function (a) {
            var n = parseInt(a);
            var letter = a.replace(n, "");
            if (letter) {
                return n + letter[0].charCodeAt() / 0xFF;
            } else {
                return n;
            }
        });
        for (var i = 0; i < version.length; ++i) {
            if (levels === i) break;
            value += version[i] / 0xFF * Math.pow(0xFF, levels - i + 1);
        }
        return value;
    };
    var v1 = getVersionHash(data0);
    var v2 = getVersionHash(data1);
    return v1 === v2 ? -1 : v1 > v2 ? 0 : 1;
};
// Returns 0 or 1, correlating to input A and input B
// Direct match returns -1
var version = compareVersion("1.254.253", "1.254.253a", 3);



私はそれらを比較する最も簡単な方法を見つける、それがあなたが望むものかどうかはわからない。コンソールのコードの下を実行すると意味があり、sort()メソッドを使うとソートされたバージョンの文字列を得ることができます。それはアルファベット順に基づいています。

"1.0" < "1.0.1" //true
var arr = ["1.0.1", "1.0", "3.2.0", "1.3"]
arr.sort();     //["1.0", "1.0.1", "1.3", "3.2.0"]



もし私が見たことのないリンクでこのアイデアがすでに訪れていたら、私を許してください。

私は、部品を以下のような加重和に変換することでいくつかの成功を収めました:

partSum = this.major * Math.Pow(10,9);
partSum += this.minor * Math.Pow(10, 6);
partSum += this.revision * Math.Pow(10, 3);
partSum += this.build * Math.Pow(10, 0);

これは比較を非常に簡単にしました(ダブルを比較)。 バージョンフィールドは決して4桁を超えません。

7.10.2.184  -> 7010002184.0
7.11.0.1385 -> 7011001385.0

私はこれが誰かを助けてくれることを願っています。複数の条件文がちょっと残酷すぎるようです。




私の2セントと働く答え:

v1 = '20.0.12'; 
v2 = '3.123.12';

compareVersion(v1,v2) // return true

function compareVersion(ver1, ver2) {
        ver1 = ver1.split('.')
        ver2 = ver2.split('.')
        var i = 0, v1, v2;
        ver1 = Array.isArray(ver1) ? ver1 : [ver1];
        /*default is true*/
        while (i < 4) {
            v1 = ver1[i]; v2 = ver2[i];
            if (!v1 || !v2) return true;
            if (v1 * 1 < v2 * 1) return false;
            i++;
        }
        return true;
    }

IE以外のブラウザーでもっとクールな答え:

 function compareVersion2(ver1, ver2) {
      ver1 = ver1.split('.').map( s => s.padStart(10) ).join('.');
      ver2 = ver2.split('.').map( s => s.padStart(10) ).join('.');
      return ver1 <= ver2;
 }



例えば、現在のjQueryのバージョンが1.8より小さいかどうかをチェックしたい場合、parseFloat( "1.10。")以降、バージョンが "1.10.1"の場合、 parseFloat($.ui.version) < 1.8 )誤った結果を返します。 1 ")は1.1返します。 "1.8" < "1.10"false評価されるため、文字列比較も間違っていfalse

だから、このようなテストが必要です

if(versionCompare($.ui.version, "1.8") < 0){
    alert("please update jQuery");
}

次の関数はこれを正しく処理します:

/** Compare two dotted version strings (like '10.2.3').
 * @returns {Integer} 0: v1 == v2, -1: v1 < v2, 1: v1 > v2
 */
function versionCompare(v1, v2) {
    var v1parts = ("" + v1).split("."),
        v2parts = ("" + v2).split("."),
        minLength = Math.min(v1parts.length, v2parts.length),
        p1, p2, i;
    // Compare tuple pair-by-pair. 
    for(i = 0; i < minLength; i++) {
        // Convert to integer if possible, because "8" > "10".
        p1 = parseInt(v1parts[i], 10);
        p2 = parseInt(v2parts[i], 10);
        if (isNaN(p1)){ p1 = v1parts[i]; } 
        if (isNaN(p2)){ p2 = v2parts[i]; } 
        if (p1 == p2) {
            continue;
        }else if (p1 > p2) {
            return 1;
        }else if (p1 < p2) {
            return -1;
        }
        // one operand is NaN
        return NaN;
    }
    // The longer tuple is always considered 'greater'
    if (v1parts.length === v2parts.length) {
        return 0;
    }
    return (v1parts.length < v2parts.length) ? -1 : 1;
}

ここではいくつかの例を示します。

// compare dotted version strings
console.assert(versionCompare("1.8",      "1.8.1")    <   0);
console.assert(versionCompare("1.8.3",    "1.8.1")    >   0);
console.assert(versionCompare("1.8",      "1.10")     <   0);
console.assert(versionCompare("1.10.1",   "1.10.1")   === 0);
// Longer is considered 'greater'
console.assert(versionCompare("1.10.1.0", "1.10.1")   >   0);
console.assert(versionCompare("1.10.1",   "1.10.1.0") <   0);
// Strings pairs are accepted
console.assert(versionCompare("1.x",      "1.x")      === 0);
// Mixed int/string pairs return NaN
console.assert(isNaN(versionCompare("1.8", "1.x")));
//works with plain numbers
console.assert(versionCompare("4", 3)   >   0);

ライブサンプルとテストスイートについてはこちらをご覧ください: http : //jsfiddle.net/mar10/8KjvP/




// Returns true if v1 is bigger than v2, and false if otherwise.
function isNewerThan(v1, v2) {
      v1=v1.split('.');
      v2=v2.split('.');
      for(var i = 0; i<Math.max(v1.length,v2.length); i++){
        if(v1[i] == undefined) return false; // If there is no digit, v2 is automatically bigger
        if(v2[i] == undefined) return true; // if there is no digit, v1 is automatically bigger
        if(v1[i] > v2[i]) return true;
        if(v1[i] < v2[i]) return false;
      }
      return false; // Returns false if they are equal
    }



私はKonsのアイデアに基づいてこれを作って、それをJavaバージョン "1.7.0_45"用に最適化しました。 これはバージョン文字列をfloatに変換するための関数です。 これは関数です:

function parseVersionFloat(versionString) {
    var versionArray = ("" + versionString)
            .replace("_", ".")
            .replace(/[^0-9.]/g, "")
            .split("."),
        sum = 0;
    for (var i = 0; i < versionArray.length; ++i) {
        sum += Number(versionArray[i]) / Math.pow(10, i * 3);
    }
    console.log(versionString + " -> " + sum);
    return sum;
}

文字列 "1.7.0_45"は1.0070000450000001に変換され、通常の比較には十分です。 ここで説明するエラー: JavaScriptで浮動小数点数の精度を処理するには? 。 任意の部分で3桁以上必要な場合は、分周器Math.pow(10, i * 3);変更できMath.pow(10, i * 3);

出力は次のようになります。

1.7.0_45         > 1.007000045
ver 1.7.build_45 > 1.007000045
1.234.567.890    > 1.23456789



私がここで望んでいた機能を見つけることができませんでした。 だから私は自分自身を書いた。 これが私の貢献です。 私は誰かがそれが役に立つと願っています。

長所:

  • 任意の長さのバージョン文字列を処理します。 '1'または '1.1.1.1.1'。

  • 指定しない場合、各値は0にデフォルト設定されます。 文字列が長かったからといって、それがより大きなバージョンであるとは限りません。 ( '1'は '1.0'および '1.0.0.0'と同じにする必要があります)。

  • 数字ではない文字列を比較します。 ( '3' <'21'は真でなければなりません。

  • ループの無駄な比較に時間を費やさないでください。 (==の比較)

  • 独自のコンパレータを選択することができます。

短所:

  • バージョン文字列の文字は扱えません。 (私はそれがどのように動作するのかわかりません?)

私のコードは、 Jonによって受け入れられた答えに似ています:

function compareVersions(v1, comparator, v2) {
    "use strict";
    var comparator = comparator == '=' ? '==' : comparator;
    if(['==','===','<','<=','>','>=','!=','!=='].indexOf(comparator) == -1) {
        throw new Error('Invalid comparator. ' + comparator);
    }
    var v1parts = v1.split('.'), v2parts = v2.split('.');
    var maxLen = Math.max(v1parts.length, v2parts.length);
    var part1, part2;
    var cmp = 0;
    for(var i = 0; i < maxLen && !cmp; i++) {
        part1 = parseInt(v1parts[i], 10) || 0;
        part2 = parseInt(v2parts[i], 10) || 0;
        if(part1 < part2)
            cmp = 1;
        if(part1 > part2)
            cmp = -1;
    }
    return eval('0' + comparator + cmp);
}

compareVersions('1.2.0', '==', '1.2'); // true
compareVersions('00001', '==', '1.0.0'); // true
compareVersions('1.2.0', '<=', '1.2'); // true
compareVersions('2.2.0', '<=', '1.2'); // false



これは、あなたのバージョン管理システムの背後にあるロジックに依存します。各数字は何を表し、どのように使用されますか。

各Subversionは開発段階を指定するための数値ですか?リリース候補3(最終版)のベータ2のアルファ1は0

ビルド版ですか?増分更新を適用していますか?

バージョン管理システムの仕組みが分かれば、アルゴリズムの作成は簡単になります。

各Subversionで9より大きい数値を許可しない場合、すべての小数点を除いて最初のものを削除すると、直線比較が可能になります。

サブバージョンのいずれかで9より大きい数値を許可する場合は、それらを比較するいくつかの方法があります。最も明白なのは、文字列を小数点で分割して各列を比較することです。

バージョン管理システムの仕組みがわからなければ、バージョン1.0.2aがリリースされたときに上記のようなプロセスを実装することができます。




再帰的なアルゴリズムでこれを行う別の方法があります。

このコードは単にArray.shiftと再帰的なものを使用しています。つまり、IE 6以降で実行できます。ご不明な点がございましたら、私のGitHubをご覧ください

(function(root, factory) {
  if (typeof exports === 'object') {
    return module.exports = factory();
  } else if (typeof define === 'function' && define.amd) {
    return define(factory);
  } else {
    return root.compareVer = factory();
  }
})(this, function() {
  'use strict';
  var _compareVer;
  _compareVer = function(newVer, oldVer) {
    var VER_RE, compareNum, isTrue, maxLen, newArr, newLen, newMatch, oldArr, oldLen, oldMatch, zerofill;
    VER_RE = /(\d+\.){1,9}\d+/;
    if (arguments.length !== 2) {
      return -100;
    }
    if (typeof newVer !== 'string') {
      return -2;
    }
    if (typeof oldVer !== 'string') {
      return -3;
    }
    newMatch = newVer.match(VER_RE);
    if (!newMatch || newMatch[0] !== newVer) {
      return -4;
    }
    oldMatch = oldVer.match(VER_RE);
    if (!oldMatch || oldMatch[0] !== oldVer) {
      return -5;
    }
    newVer = newVer.replace(/^0/, '');
    oldVer = oldVer.replace(/^0/, '');
    if (newVer === oldVer) {
      return 0;
    } else {
      newArr = newVer.split('.');
      oldArr = oldVer.split('.');
      newLen = newArr.length;
      oldLen = oldArr.length;
      maxLen = Math.max(newLen, oldLen);
      zerofill = function() {
        newArr.length < maxLen && newArr.push('0');
        oldArr.length < maxLen && oldArr.push('0');
        return newArr.length !== oldArr.length && zerofill();
      };
      newLen !== oldLen && zerofill();
      if (newArr.toString() === oldArr.toString()) {
        if (newLen > oldLen) {
          return 1;
        } else {
          return -1;
        }
      } else {
        isTrue = -1;
        compareNum = function() {
          var _new, _old;
          _new = ~~newArr.shift();
          _old = ~~oldArr.shift();
          _new > _old && (isTrue = 1);
          return _new === _old && newArr.length > 0 && compareNum();
        };
        compareNum();
        return isTrue;
      }
    }
  };
  return _compareVer;
});

まあ、このコードが誰かを助けることを願っています。

ここにテストがあります。

console.log(compareVer("0.0.2","0.0.1"));//1
console.log(compareVer("0.0.10","0.0.1")); //1
console.log(compareVer("0.0.10","0.0.2")); //1
console.log(compareVer("0.9.0","0.9")); //1
console.log(compareVer("0.10.0","0.9.0")); //1
console.log(compareVer("1.7", "1.07")); //1
console.log(compareVer("1.0.07", "1.0.007")); //1

console.log(compareVer("0.3","0.3")); //0
console.log(compareVer("0.0.3","0.0.3")); //0
console.log(compareVer("0.0.3.0","0.0.3.0")); //0
console.log(compareVer("00.3","0.3")); //0
console.log(compareVer("00.3","00.3")); //0
console.log(compareVer("01.0.3","1.0.3")); //0
console.log(compareVer("1.0.3","01.0.3")); //0

console.log(compareVer("0.2.0","1.0.0")); //-1
console.log(compareVer('0.0.2.2.0',"0.0.2.3")); //-1
console.log(compareVer('0.0.2.0',"0.0.2")); //-1
console.log(compareVer('0.0.2',"0.0.2.0")); //-1
console.log(compareVer("1.07", "1.7")); //-1
console.log(compareVer("1.0.007", "1.0.07")); //-1

console.log(compareVer()); //-100
console.log(compareVer("0.0.2")); //-100
console.log(compareVer("0.0.2","0.0.2","0.0.2")); //-100
console.log(compareVer(1212,"0.0.2")); //-2
console.log(compareVer("0.0.2",1212)); //-3
console.log(compareVer('1.abc.2',"1.0.2")); //-4
console.log(compareVer('1.0.2',"1.abc.2")); //-5



これはピリオドで区切られた任意の長さの数値バージョンで有効です。 myVersionが> = minimumVersionの場合にのみtrueを返し、バージョン1が1.0未満、バージョン1.1が1.1.0未満、というように仮定します。 数値の受け入れ(文字列への変換)や16進数の区切りや、区切り文字を動的にするなどの追加条件を追加するのはかなり簡単です(区切り文字パラメータを追加して "。"をパラメータに置き換えます)

function versionCompare(myVersion, minimumVersion) {

    var v1 = myVersion.split("."), v2 = minimumVersion.split("."), minLength;   

    minLength= Math.min(v1.length, v2.length);

    for(i=0; i<minLength; i++) {
        if(Number(v1[i]) > Number(v2[i])) {
            return true;
        }
        if(Number(v1[i]) < Number(v2[i])) {
            return false;
        }           
    }

    return (v1.length >= v2.length);
}

いくつかのテストがあります:

console.log(versionCompare("4.4.0","4.4.1"));
console.log(versionCompare("5.24","5.2"));
console.log(versionCompare("4.1","4.1.2"));
console.log(versionCompare("4.1.2","4.1"));
console.log(versionCompare("4.4.4.4","4.4.4.4.4"));
console.log(versionCompare("4.4.4.4.4.4","4.4.4.4.4"));
console.log(versionCompare("0","1"));
console.log(versionCompare("1","1"));
console.log(versionCompare("","1"));
console.log(versionCompare("10.0.1","10.1"));

代わりにここでは再帰的なバージョンです

function versionCompare(myVersion, minimumVersion) {
  return recursiveCompare(myVersion.split("."),minimumVersion.split("."),Math.min(myVersion.length, minimumVersion.length),0);
}

function recursiveCompare(v1, v2,minLength, index) {
  if(Number(v1[index]) < Number(v2[index])) {
    return false;
  }
  if(Number(v1[i]) < Number(v2[i])) {
    return true;
    }
  if(index === minLength) {
    return (v1.length >= v2.length);
  }
  return recursiveCompare(v1,v2,minLength,index+1);
}



セーバー

npmによって使用されるセマンティックバージョンパーサー。

$ npm install semver

var semver = require('semver');

semver.diff('3.4.5', '4.3.7') //'major'
semver.diff('3.4.5', '3.3.7') //'minor'
semver.gte('3.4.8', '3.4.7') //true
semver.ltr('3.4.8', '3.4.7') //false

semver.valid('1.2.3') // '1.2.3'
semver.valid('a.b.c') // null
semver.clean(' =v1.2.3 ') // '1.2.3'
semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
semver.gt('1.2.3', '9.8.7') // false
semver.lt('1.2.3', '9.8.7') // true

var versions = [ '1.2.3', '3.4.5', '1.0.2' ]
var max = versions.sort(semver.rcompare)[0]
var min = versions.sort(semver.compare)[0]
var max = semver.maxSatisfying(versions, '*')

セマンティックバージョニングリンク
https://www.npmjs.com/package/semver#prerelease-identifiers




ソート前のバージョンの前処理は、parseIntが不要に複数回呼び出されないことを意味します。 マイケル・ディールの提案に似たArray#mapを使用して、私は標準的な3部のセーバーの最新バージョンを見つけるために使っているソートです:

var semvers = ["0.1.0", "1.0.0", "1.1.0", "1.0.5"];

var versions = semvers.map(function(semver) {
    return semver.split(".").map(function(part) {
        return parseInt(part);
    });
});

versions.sort(function(a, b) {
    if (a[0] < b[0]) return 1;
    else if (a[0] > b[0]) return -1;
    else if (a[1] < b[1]) return 1;
    else if (a[1] > b[1]) return -1;
    else if (a[2] < b[2]) return 1;
    else if (a[2] > b[2]) return -1;
    return 0;
});

var newest = versions[0].join(".");
console.log(newest); // "1.1.0"