以下是软件版本号:

"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.0.0.0", "1.0.1.0", "2.0.0.0", "2.0.0.1", "2.0.1.0"

这样可以更清楚地看到背后的想法。 但是,我怎样才能把它转换成计算机程序呢?


当前回答

2017答:

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

compareVersions(v1,v2) 
// return positive: v1 > v2, zero:v1 == v2, negative: v1 < v2 
function compareVersions(v1, v2) {
        v1= v1.split('.')
        v2= v2.split('.')
        var len = Math.max(v1.length,v2.length)
        /*default is true*/
        for( let i=0; i < len; i++)
            v1 = Number(v1[i] || 0);
            v2 = Number(v2[i] || 0);
            if (v1 !== v2) return v1 - v2 ;
            i++;
        }
        return 0;
    }

最简单的现代浏览器代码:

 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;
 }

这里的想法是比较数字,但以字符串的形式。为了使比较工作,两个字符串必须在相同的长度。所以:

"123" > "99"变成"123" > "099" 填充短数字“修复”比较

这里我用0填充每个部分,长度为10。然后使用简单的字符串比较来得到答案

例子:

var ver1 = '0.2.10', ver2=`0.10.2`
//become 
ver1 = '0000000000.0000000002.0000000010'
ver2 = '0000000000.0000000010.0000000002'
// then it easy to see that
ver1 <= ver2 // true

其他回答

2020年(大多数时候)正确的JavaScript答案

Nina Scholz在2020年3月和Sid Vishnoi在2020年4月都给出了现代的答案:

var versions = ["2.0.1", "2.0", "1.0", "1.0.1", "2.0.0.1"];

versions.sort((a, b) => 
   a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })
);

console.log(versions);

localCompare已经存在一段时间了

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator

但是1.0a和1.0.1呢

localCompare不能解决这个问题,仍然返回1.0.1,1.0a

迈克尔·迪尔(Michael Deal)在他的(略长且复杂的)解决方案中已经在2013年解决了这个问题

他将数字转换为另一种进位,以便更好地排序

他的回答让我思考……

666 -不要用数字思考- 999

排序是基于ASCII值的字母数字排序,所以让我们(ab)使用ASCII作为“基”

我的解决方案是将1.0.2.1到b.a.c.b转换为bacb,然后排序

这解决了1.1 vs. 1.0.0.0.1: bb vs. baaab

立即用baa和bab符号解决了1.0a和1.0.1排序问题

转换是通过:

    const str = s => s.match(/(\d+)|[a-z]/g)
                      .map(c => c == ~~c ? String.fromCharCode(97 + c) : c);

=计算ASCII值0…999数字,否则连字母

1.0 > > >(“0”,“1”” " ] >>> [ " b”、“”、“”)

为了便于比较,没有必要使用.join("")将其连接到一个字符串。

Oneliner

const sortVersions=(x,v=s=>s.match(/(\d+)|[a-z]/g)
                            .map(c=>c==~~c?String.fromCharCode(97+c):c))
                    =>x.sort((a,b)=>v(b)<v(a)?1:-1)

测试代码片段:

function log(label,val){ document.body.append(label,String(val).replace(/,/g," - "),document.createElement("BR")); } let v = ["1.90.1", "1.9.1", "1.89", "1.090", "1.2", "1.0a", "1.0.1", "1.10", "1.0.0a"]; log('not sorted input :',v); v.sort((a, b) => a.localeCompare(b,undefined,{numeric:true,sensitivity:'base' })); log(' locale Compare :', v); // 1.0a AFTER 1.0.1 const str = s => s.match(/(\d+)|[a-z]/g) .map(c => c == ~~c ? String.fromCharCode(97 + c) : c); const versionCompare = (a, b) => { a = str(a); b = str(b); return b < a ? 1 : a == b ? 0 : -1; } v.sort(versionCompare); log('versionCompare:', v);

注意1.090是如何在两个结果中排序的。

我的代码不会解决一个答案中提到的001.012.001符号,但是localeCompare正确地解决了这部分挑战。

你可以结合这两种方法:

当涉及字母时,使用.localCompare或versionCompare进行排序

最终的JavaScript解决方案

const sortVersions = ( x, V = s => s.match(/[a-z]|\d+/g)。Map (c => c==~~c ?String.fromCharCode(97 + c): c) => x.sort((a, b) => (a + b).match(/[a-z]/) ? V (b) < V (a) ?1: -1 : a.localeCompare(b, 0, {numeric: true})) 让v =[" 1.90.1”、“1.090”、“1.0”、“1.0.1”,“1.0.0a”,“1.0.0b”、“1.0.0.1”); console.log (sortVersions (v));

你可以使用带有选项的String#localeCompare

sensitivity Which differences in the strings should lead to non-zero result values. Possible values are: "base": Only strings that differ in base letters compare as unequal. Examples: a ≠ b, a = á, a = A. "accent": Only strings that differ in base letters or accents and other diacritic marks compare as unequal. Examples: a ≠ b, a ≠ á, a = A. "case": Only strings that differ in base letters or case compare as unequal. Examples: a ≠ b, a = á, a ≠ A. "variant": Strings that differ in base letters, accents and other diacritic marks, or case compare as unequal. Other differences may also be taken into consideration. Examples: a ≠ b, a ≠ á, a ≠ A. The default is "variant" for usage "sort"; it's locale dependent for usage "search". numeric Whether numeric collation should be used, such that "1" < "2" < "10". Possible values are true and false; the default is false. This option can be set through an options property or through a Unicode extension key; if both are provided, the options property takes precedence. Implementations are not required to support this property.

var版本=[" 2.0.1”、“2.0”、“1.0”、“1.0.1”,“2.0.0.1”); 版本。sort((a, b) => a.localeCompare(b, undefined, {numeric: true,灵敏度:'base'})); console.log(版本);

下面是一个版本,它对版本字符串进行排序,而不分配任何子字符串或数组。由于它分配的对象更少,GC要做的工作也就更少。

有一对分配(允许重用getVersionPart方法),但是如果您对性能非常敏感,您可以扩展它以完全避免分配。

const compareVersionStrings : (a: string, b: string) => number = (a, b) =>
{
    var ia = {s:a,i:0}, ib = {s:b,i:0};
    while (true)
    {
        var na = getVersionPart(ia), nb = getVersionPart(ib);

        if (na === null && nb === null)
            return 0;
        if (na === null)
            return -1;
        if (nb === null)
            return 1;
        if (na > nb)
            return 1;
        if (na < nb)
            return -1;
    }
};

const zeroCharCode = '0'.charCodeAt(0);

const getVersionPart = (a : {s:string, i:number}) =>
{
    if (a.i >= a.s.length)
        return null;

    var n = 0;
    while (a.i < a.s.length)
    {
        if (a.s[a.i] === '.')
        {
            a.i++;
            break;
        }

        n *= 10;
        n += a.s.charCodeAt(a.i) - zeroCharCode;
        a.i++;
    }
    return n;
}

我必须比较我的扩展版本,但我没有 在这里找到一个可行的解决方案。在比较1.89 > 1.9或1.24.1 == 1.240.1时,几乎所有提议的期权都被打破了

这里,我从仅在最后的记录1.1 == 1.10和1.10.1 > 1.1.1中0下降的事实开始

compare_version = (new_version, old_version) => {
    new_version = new_version.split('.');
    old_version = old_version.split('.');
    for(let i = 0, m = Math.max(new_version.length, old_version.length); i<m; i++){
        //compare text
        let new_part = (i<m-1?'':'.') + (new_version[i] || 0)
        ,   old_part = (i<m-1?'':'.') + (old_version[i] || 0);
        //compare number (I don’t know what better)
      //let new_part = +((i<m-1?0:'.') + new_version[i]) || 0
      //,   old_part = +((i<m-1?0:'.') + old_version[i]) || 0;
        //console.log(new_part, old_part);
        if(old_part > new_part)return 0;    //change to -1 for sort the array
        if(new_part > old_part)return 1
    }
    return 0
};
compare_version('1.0.240.1','1.0.240.1');   //0
compare_version('1.0.24.1','1.0.240.1');    //0
compare_version('1.0.240.89','1.0.240.9');  //0
compare_version('1.0.24.1','1.0.24');       //1

我不是一个大专家,但我构建了简单的代码来比较两个版本,将第一个返回值更改为-1以对版本数组进行排序

['1.0.240', '1.0.24', '1.0.240.9', '1.0.240.89'].sort(compare_version)
//results ["1.0.24", "1.0.240", "1.0.240.89", "1.0.240.9"]

和短版本的比较全字符串

c=e=>e.split('.').map((e,i,a)=>e[i<a.length-1?'padStart':'padEnd'](5)).join('');

//results "    1    0  2409    " > "    1    0  24089   "

c('1.0.240.9')>c('1.0.240.89')              //true

如果您有意见或改进,请不要犹豫提出建议。

下面是一个适合Array使用的coffeescript实现。从其他答案中得到启发:

# Returns > 0 if v1 > v2 and < 0 if v1 < v2 and 0 if v1 == v2
compareVersions = (v1, v2) ->
  v1Parts = v1.split('.')
  v2Parts = v2.split('.')
  minLength = Math.min(v1Parts.length, v2Parts.length)
  if minLength > 0
    for idx in [0..minLength - 1]
      diff = Number(v1Parts[idx]) - Number(v2Parts[idx])
      return diff unless diff is 0
  return v1Parts.length - v2Parts.length