1. ホーム
  2. ジャバスクリプト

[解決済み】ソフトウェアのバージョン番号をjsで比較する方法は?(数字のみ)

2022-04-08 15:56:03

質問

ソフトウェアのバージョン番号はこちらです。

"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"

考え方は簡単です...。 1桁目を読み、2桁目を読み、3桁目を読む......。 でも、バージョン番号を浮動小数点数に変換することができない......。 また、バージョン番号はこのように見ることができます。

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

と、このように、背後にあるアイデアが何であるかがより明確になっています。 しかし、これをどのようにコンピュータのプログラムに変換するのでしょうか? どなたか、この仕分け方法についてご存知の方はいらっしゃいますか?ありがとうございました。

どのように解決するのですか?

この比較を行うための基本的な考え方は Array.split を使って入力文字列から部品の配列を取得し、2つの配列の部品のペアを比較します。部品が等しくない場合は、どちらのバージョンが小さいかを知ることができます。

注意すべき点がいくつかあります。

  1. 各ペアのパーツはどのように比較すればよいのでしょうか?質問では数値で比較したいのですが、数字だけで構成されていないバージョン文字列(例:"1.0a")がある場合はどうすればよいでしょうか?
  2. 一方のバージョン文字列が他方より多くの部分を持つ場合、どうすればよいでしょうか。おそらく "1.0" は "1.0.1" よりも小さいと考えるべきですが、"1.0.0" はどうでしょうか?

以下は直接使える実装のコードです( ドキュメント付きリスト ):

function versionCompare(v1, v2, options) {
    var lexicographical = options && options.lexicographical,
        zeroExtend = options && options.zeroExtend,
        v1parts = v1.split('.'),
        v2parts = v2.split('.');

    function isValidPart(x) {
        return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x);
    }

    if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
        return NaN;
    }

    if (zeroExtend) {
        while (v1parts.length < v2parts.length) v1parts.push("0");
        while (v2parts.length < v1parts.length) v2parts.push("0");
    }

    if (!lexicographical) {
        v1parts = v1parts.map(Number);
        v2parts = v2parts.map(Number);
    }

    for (var i = 0; i < v1parts.length; ++i) {
        if (v2parts.length == i) {
            return 1;
        }

        if (v1parts[i] == v2parts[i]) {
            continue;
        }
        else if (v1parts[i] > v2parts[i]) {
            return 1;
        }
        else {
            return -1;
        }
    }

    if (v1parts.length != v2parts.length) {
        return -1;
    }

    return 0;
}

このバージョンではパーツを比較します 当然 また、"1.7" は "1.7.0" よりも小さいと見なします。比較モードを辞書式に変更したり、オプションの第3引数を用いて短いバージョンの文字列を自動的にゼロパディングしたりすることができます。

ユニットテストを実行するJSFiddleがあります。 こちら を少し拡張したものです。 ripper234さんの作品 (ありがとうございます)。

重要なお知らせです。 このコードでは Array.map Array.every もし、これらのメソッドに対応する必要がある場合は、不足するメソッドのポリフィルを提供する必要があります。