js를 사용하여 소프트웨어 버전 번호를 비교하는 방법은 무엇입니까? (숫자 만)
소프트웨어 버전 번호는 다음과 같습니다.
"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"
그리고 이것은 뒤에있는 아이디어가 무엇인지 알기 더 명확합니다 ... 그러나 그것을 컴퓨터 프로그램으로 변환하는 방법 ?? 이것을 분류하는 방법에 대한 아이디어가 있습니까? 감사합니다.
이 비교를위한 기본 아이디어 Array.split
는 입력 문자열에서 부품 배열을 가져온 다음 두 배열에서 부품 쌍을 비교하는 데 사용 하는 것입니다 . 부품이 동일하지 않은 경우 어떤 버전이 더 작은 지 알고 있습니다.
명심해야 할 몇 가지 중요한 세부 사항이 있습니다.
- 각 쌍의 부품을 어떻게 비교해야합니까? 질문은 숫자로 비교하려고하지만 숫자만으로 구성되지 않은 버전 문자열 (예 : "1.0a")이있는 경우 어떻게해야합니까?
- 한 버전 문자열에 다른 버전 문자열이 더 많은 경우 어떻게됩니까? "1.0"은 "1.0.1"보다 작아야하지만 "1.0.0"은 어떻습니까?
직접 사용할 수있는 구현 코드는 다음과 같습니다 ( documents with documentation ).
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"보다 작은 것으로 간주합니다. 비교 모드는 사전 식으로 변경 될 수 있으며 더 짧은 버전의 문자열은 선택적 세 번째 인수를 사용하여 자동으로 0으로 채워질 수 있습니다.
여기에 "단위 테스트"를 실행하는 JSFiddle이 있습니다 . ripper234 작품의 약간 확장 된 버전입니다 (감사합니다).
중요 사항 : 이 코드를 사용 Array.map
하고 Array.every
당신이 누락 된 방법에 대한 polyfills을 제공해야합니다 사람들을 지원해야하는 경우가 9보다 이전의 IE 버전에서 실행되지 않음을 의미합니다.
셈버
npm에서 사용되는 시맨틱 버전 파서.
$ npm 설치 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
// 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"));
이 매우 작지만 매우 빠른 비교 기능은 세그먼트마다 길이 와 숫자 크기 의 버전 번호를 사용합니다 .
리턴 값 :
- 다수 < 0
은 <B의 경우
- 숫자 > 0
경우> B
- 0
A = B가되는 경우
따라서 Array.sort ()의 비교 함수 로 사용할 수 있습니다 .
편집 : "1"과 "1.0.0"을 동일하게 인식하기 위해 후행 0을 제거하는 버그 수정 버전
function cmpVersions (a, b) {
var i, diff;
var regExStrip0 = /(\.0+)+$/;
var segmentsA = a.replace(regExStrip0, '').split('.');
var segmentsB = b.replace(regExStrip0, '').split('.');
var l = Math.min(segmentsA.length, segmentsB.length);
for (i = 0; i < l; i++) {
diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10);
if (diff) {
return diff;
}
}
return segmentsA.length - segmentsB.length;
}
// TEST
console.log(
['2.5.10.4159',
'1.0.0',
'0.5',
'0.4.1',
'1',
'1.1',
'0.0.0',
'2.5.0',
'2',
'0.0',
'2.5.10',
'10.5',
'1.25.4',
'1.2.15'].sort(cmpVersions));
// Result:
// ["0.0.0", "0.0", "0.4.1", "0.5", "1.0.0", "1", "1.1", "1.2.15", "1.25.4", "2", "2.5.0", "2.5.10", "2.5.10.4159", "10.5"]
http://java.com/js/deployJava.js 에서 가져 왔습니다 .
// return true if 'installed' (considered as a JRE version string) is
// greater than or equal to 'required' (again, a JRE version string).
compareVersions: function (installed, required) {
var a = installed.split('.');
var b = required.split('.');
for (var i = 0; i < a.length; ++i) {
a[i] = Number(a[i]);
}
for (var i = 0; i < b.length; ++i) {
b[i] = Number(b[i]);
}
if (a.length == 2) {
a[2] = 0;
}
if (a[0] > b[0]) return true;
if (a[0] < b[0]) return false;
if (a[1] > b[1]) return true;
if (a[1] < b[1]) return false;
if (a[2] > b[2]) return true;
if (a[2] < b[2]) return false;
return true;
}
내가 원하는 것을하는 함수를 찾을 수 없습니다. 그래서 나는 내 자신을 썼습니다. 이것이 나의 공헌입니다. 누군가가 유용하다고 생각합니다.
장점 :
임의 길이의 버전 문자열을 처리합니다. '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
간단하고 짧은 기능 :
function isNewerVersion (oldVer, newVer) {
const oldParts = oldVer.split('.')
const newParts = newVer.split('.')
for (var i = 0; i < newParts.length; i++) {
const a = parseInt(newParts[i]) || 0
const b = parseInt(oldParts[i]) || 0
if (a > b) return true
if (a < b) return false
}
return false
}
테스트 :
isNewerVersion('1.0', '2.0') // true
isNewerVersion('1.0', '1.0.1') // true
isNewerVersion('1.0.1', '1.0.10') // true
isNewerVersion('1.0.1', '1.0.1') // false
isNewerVersion('2.0', '1.0') // false
isNewerVersion('2', '1.0') // false
isNewerVersion('2.0.0.0.0.1', '2.1') // true
isNewerVersion('2.0.0.0.0.1', '2.0') // false
version_compare()
php.js 프로젝트에서 기능 을 확인하십시오 . PHP version_compare()
와 비슷합니다 .
다음과 같이 간단히 사용할 수 있습니다.
version_compare('2.0', '2.0.0.1', '<');
// returns true
이 아이디어가 이미 보지 못한 링크로 방문한 경우 용서하십시오.
다음과 같이 부품을 가중 합계로 변환하는 데 성공했습니다.
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
여러 조건이 약간 과도하게 보이므로 이것이 누군가에게 도움이되기를 바랍니다.
2017 년 답변 :
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 (lake of padStart
)를 지원하지 않는 브라우저에 대한 더 멋진 답변 은 다음과 같습니다.
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" // return false, but it wrong "123" "> "099" // but padding the short number with zeros make the comparision to be right
따라서 솔루션의 아이디어는 버전의 모든 부분을 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
다음은 임의의 수의 하위 버전, 채워진 0 및 문자가있는 숫자 (1.0.0b3)와 함께 작동하는 또 다른 짧은 버전입니다.
function compareVer(a, b)
{
//treat non-numerical characters as lower version
//replacing them with a negative number based on charcode of each character
function fix(s)
{
return "." + (s.toLowerCase().charCodeAt(0) - 2147483647) + ".";
}
a = ("" + a).replace(/[^0-9\.]/g, fix).split('.');
b = ("" + b).replace(/[^0-9\.]/g, fix).split('.');
var c = Math.max(a.length, b.length);
for (var i = 0; i < c; i++)
{
//convert to integer the most efficient way
a[i] = ~~a[i];
b[i] = ~~b[i];
if (a[i] > b[i])
return 1;
else if (a[i] < b[i])
return -1;
}
return 0;
}
산출:
0 : a = b
1 : a> b
-1 : a <b
1.0.0.0.0.0 = 1.0
1.0 < 1.0.1
1.0b1 < 1.0
1.0a < 1.0b
1.1 > 1.0.1b
1.1alpha < 1.1beta
1.1rc1 > 1.1beta
1.0001 > 1.00000.1.0.0.0.01
/*use strict*/
function compareVer(a, b)
{
//treat non-numerical characters as lover version
//replacing them with a negative number based on charcode of each character
function fix(s)
{
return "." + (s.toLowerCase().charCodeAt(0) - 2147483647) + ".";
}
a = ("" + a).replace(/[^0-9\.]/g, fix).split('.');
b = ("" + b).replace(/[^0-9\.]/g, fix).split('.');
var c = Math.max(a.length, b.length);
for (var i = 0; i < c; i++)
{
//convert to integer the most efficient way
a[i] = ~~a[i];
b[i] = ~~b[i];
if (a[i] > b[i])
return 1;
else if (a[i] < b[i])
return -1;
}
return 0;
}
var type = {
"-1": " < ",
"0": " = ",
"1": " > "
};
var list = [
["1.0.0.0.0.0", "1.0"],
["1.0", "1.0.1"],
["1.0b1", "1.0"],
["1.0a", "1.0b"],
["1.1", "1.0.1b"],
["1.1alpha", "1.1beta"],
["1.1rc1", "1.1beta"],
["1.0001", "1.00000.1.0.0.0.01"]
];
for(var i = 0; i < list.length; i++)
{
console.log(list[i][0] + type[compareVer(list[i][0], list[i][1])] + list[i][1]);
}
https://jsfiddle.net/vanowm/p7uvtbor/
// 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
}
이 replace()
함수는 문자열에서 첫 번째 항목 만 바꿉니다. 그래서, 교체 할 수 있습니다 .
로 ,
. 그런 다음 모두 삭제 .
하고 ,
to를 .
다시 만들고 파싱하도록 구문 분석하십시오.
for(i=0; i<versions.length; i++) {
v = versions[i].replace('.', ',');
v = v.replace(/\./g, '');
versions[i] = parseFloat(v.replace(',', '.'));
}
마지막으로 정렬하십시오.
versions.sort();
이 블로그 게시물을 확인하십시오 . 이 기능은 숫자 버전 번호에서 작동합니다.
function compVersions(strV1, strV2) {
var nRes = 0
, parts1 = strV1.split('.')
, parts2 = strV2.split('.')
, nLen = Math.max(parts1.length, parts2.length);
for (var i = 0; i < nLen; i++) {
var nP1 = (i < parts1.length) ? parseInt(parts1[i], 10) : 0
, nP2 = (i < parts2.length) ? parseInt(parts2[i], 10) : 0;
if (isNaN(nP1)) { nP1 = 0; }
if (isNaN(nP2)) { nP2 = 0; }
if (nP1 != nP2) {
nRes = (nP1 > nP2) ? 1 : -1;
break;
}
}
return nRes;
};
compVersions('10', '10.0'); // 0
compVersions('10.1', '10.01.0'); // 0
compVersions('10.0.1', '10.0'); // 1
compVersions('10.0.1', '10.1'); // -1
예를 들어, 현재 jQuery 버전이 1.8보다 작은 지 확인하려는 경우 parseFloat ( "1.10.1")이 반환하므로 버전이 "1.10.1"인 경우 잘못된 결과를 parseFloat($.ui.version) < 1.8 )
제공 합니다 . 으로 평가 되므로 문자열 비교도 잘못 됩니다 .1.1
"1.8" < "1.10"
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/
다음은 다른 답변에서 영감을 얻은 Array.sort와 함께 사용하기에 적합한 커피 스크립트 구현입니다.
# 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
버전 정렬을위한 노드 모듈을 작성했습니다. 여기서 찾을 수 있습니다 : version-sort
특징 :
- 시퀀스 제한 없음 '1.0.1.5.53.54654.114.1.154.45'작동
- 시퀀스 길이 제한 없음 : '1.1546515465451654654654654138754431574364321353734'작동
- 버전별로 객체를 정렬 할 수 있습니다 (README 참조)
- 단계 (알파, 베타, rc1, rc2 등)
다른 기능이 필요한 경우 언제든지 주저하지 마십시오.
마침표로 구분 된 모든 길이의 숫자 버전에서 작동합니다. 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);
}
아이디어는 두 가지 버전을 비교하고 가장 큰 버전을 알고 있습니다. "."을 삭제합니다 벡터의 각 위치를 다른 위치와 비교합니다.
// Return 1 if a > b
// Return -1 if a < b
// Return 0 if a == b
function compareVersions(a_components, b_components) {
if (a_components === b_components) {
return 0;
}
var partsNumberA = a_components.split(".");
var partsNumberB = b_components.split(".");
for (var i = 0; i < partsNumberA.length; i++) {
var valueA = parseInt(partsNumberA[i]);
var valueB = parseInt(partsNumberB[i]);
// A bigger than B
if (valueA > valueB || isNaN(valueB)) {
return 1;
}
// B bigger than A
if (valueA < valueB) {
return -1;
}
}
}
나는 그것들을 비교하는 가장 간단한 방법을 찾았습니다. 원하는 것인지 확실하지 않습니다. 콘솔에서 아래 코드를 실행하면 의미가 있으며 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"]
여기의 대부분의 답변보다 덜 장황한 답변
/**
* Compare two semver versions. Returns true if version A is greater than
* version B
* @param {string} versionA
* @param {string} versionB
* @returns {boolean}
*/
export const semverGreaterThan = function(versionA, versionB){
var versionsA = versionA.split(/\./g),
versionsB = versionB.split(/\./g)
while (versionsA.length || versionsB.length) {
var a = Number(versionsA.shift()), b = Number(versionsB.shift())
if (a == b)
continue
return (a > b || isNaN(b))
}
return false
}
숫자로 변환 한 다음 크기별로 정렬 할 수 없습니까? 길이가 <4 인 숫자에 0을 추가하십시오.
콘솔에서 놀았습니다 :
$(["1.0.0.0", "1.0.1.0", "2.0.0.0", "2.0.0.1", "2.0.1", "3.0"]).each(function(i,e) {
var n = e.replace(/\./g,"");
while(n.length < 4) n+="0" ;
num.push( +n )
});
버전이 클수록 숫자가 커집니다. 편집 : 아마도 더 큰 버전 시리즈를 고려하여 조정해야 할 것입니다.
이것은 깔끔한 트릭입니다. 특정 범위의 값 사이에서 숫자 값을 처리하는 경우 버전 개체의 각 수준에 값을 할당 할 수 있습니다. 예를 들어 여기서 "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);
같은 I 버전 에서 @ mar10 , 내 관점에서, misusage의 기회가 있지만 (버전과 호환되는 경우 그렇지 않은 것 같다 시맨틱 버전의 문서,하지만 일부 "빌드 번호"를 사용하는 경우 경우가 있습니다 ) :
versionCompare( '1.09', '1.1'); // returns 1, which is wrong: 1.09 < 1.1
versionCompare('1.702', '1.8'); // returns 1, which is wrong: 1.702 < 1.8
여기서 문제는 버전 번호의 하위 번호가 경우에 따라 후행 0으로 잘라 낸 것입니다 (적어도 다른 소프트웨어를 사용하는 동안 최근에 본 것처럼). 수의 합리적인 부분과 비슷합니다.
5.17.2054 > 5.17.2
5.17.2 == 5.17.20 == 5.17.200 == ...
5.17.2054 > 5.17.20
5.17.2054 > 5.17.200
5.17.2054 > 5.17.2000
5.17.2054 > 5.17.20000
5.17.2054 < 5.17.20001
5.17.2054 < 5.17.3
5.17.2054 < 5.17.30
그러나 첫 번째 (또는 첫 번째와 두 번째) 버전 하위 번호는 항상 실제로 동일한 정수 값으로 처리됩니다.
이런 종류의 버전 관리를 사용하는 경우 예제에서 몇 줄만 변경할 수 있습니다.
// replace this:
p1 = parseInt(v1parts[i], 10);
p2 = parseInt(v2parts[i], 10);
// with this:
p1 = i/* > 0 */ ? parseFloat('0.' + v1parts[i], 10) : parseInt(v1parts[i], 10);
p2 = i/* > 0 */ ? parseFloat('0.' + v2parts[i], 10) : parseInt(v2parts[i], 10);
첫 번째 제외한 모든 하위 번호를 float로서 비교할 수 있도록, 그래서 09
및 1
될 것입니다 0.09
및 0.1
그에 따라 적절하게이 방법을 비교 하였다. 2054
그리고 3
될 것입니다 0.2054
및 0.3
.
완전한 버전은 다음과 같습니다 ( @ mar10의 신용 ) :
/** 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 = i/* > 0 */ ? parseFloat('0.' + v1parts[i], 10) : parseInt(v1parts[i], 10);;
p2 = i/* > 0 */ ? parseFloat('0.' + v2parts[i], 10) : 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;
}
추신 : 속도는 느리지 만 문자열이 실제로 문자 배열이라는 사실을 작동시키는 동일한 비교 함수를 재사용하는 것이 가능합니다.
function cmp_ver(arr1, arr2) {
// fill the tail of the array with smaller length with zeroes, to make both array have the same length
while (min_arr.length < max_arr.length) {
min_arr[min_arr.lentgh] = '0';
}
// compare every element in arr1 with corresponding element from arr2,
// but pass them into the same function, so string '2054' will act as
// ['2','0','5','4'] and string '19', in this case, will become ['1', '9', '0', '0']
for (i: 0 -> max_length) {
var res = cmp_ver(arr1[i], arr2[i]);
if (res !== 0) return res;
}
}
Kons 아이디어를 기반으로하여이를 Java 버전 "1.7.0_45"에 맞게 최적화했습니다. 버전 문자열을 부동 소수점으로 변환하는 기능 일뿐입니다. 이것은 기능입니다 :
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);
.
출력은 다음과 같습니다.
1.7.0_45 > 1.007000045
ver 1.7.build_45 > 1.007000045
1.234.567.890 > 1.23456789
나는 버전 비교와 같은 문제가 있었지만 아마도 어떤 것을 포함하는 버전 (예 : 점이 아닌 분리기, rc1, rc2와 같은 확장 ...)이 있습니다.
기본적으로 버전 문자열을 숫자와 숫자가 아닌 숫자로 나누고 유형에 따라 비교하려고하는 이것을 사용했습니다.
function versionCompare(a,b) {
av = a.match(/([0-9]+|[^0-9]+)/g)
bv = b.match(/([0-9]+|[^0-9]+)/g)
for (;;) {
ia = av.shift();
ib = bv.shift();
if ( (typeof ia === 'undefined') && (typeof ib === 'undefined') ) { return 0; }
if (typeof ia === 'undefined') { ia = '' }
if (typeof ib === 'undefined') { ib = '' }
ian = parseInt(ia);
ibn = parseInt(ib);
if ( isNaN(ian) || isNaN(ibn) ) {
// non-numeric comparison
if (ia < ib) { return -1;}
if (ia > ib) { return 1;}
} else {
if (ian < ibn) { return -1;}
if (ian > ibn) { return 1;}
}
}
}
예를 들어 "1.01"=== "1.1"또는 "1.8"< "1.71"과 같은 가정이 있습니다. 시맨틱 버전 관리 2.0.0에 지정된대로 "1.0.0-rc.1"< "1.0.0"을 관리하지 못합니다.
정렬 전에 버전을 전처리한다는 것은 parseInt가 불필요하게 여러 번 호출되지 않음을 의미합니다. Michael Deal의 제안과 유사한 Array # map을 사용하여 표준 3 파트 semver의 최신 버전을 찾는 데 사용하는 정렬은 다음과 같습니다.
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"
짧고 간단하면서도 강력하기 때문에 공유 가치가 있다고 생각합니다. 숫자 비교 만 사용합니다. 일반적으로 version2가 version1보다 최신 버전인지 확인하고 해당되는 경우 true를 반환합니다. 버전 1 : 1.1.1 및 버전 2 : 1.1.2가 있다고 가정하십시오. 버전 1의 경우 (1 + 0.1), (1.1 + 0.01) 및 버전 2의 경우 (1 + 0.1), (1.1 + 0.02)와 같이 파트를 추가하는 두 버전의 각 부분을 거치게됩니다.
function compareVersions(version1, version2) {
version1 = version1.split('.');
version2 = version2.split('.');
var maxSubVersionLength = String(Math.max.apply(undefined, version1.concat(version2))).length;
var reduce = function(prev, current, index) {
return parseFloat(prev) + parseFloat('0.' + Array(index + (maxSubVersionLength - String(current).length)).join('0') + current);
};
return version1.reduce(reduce) < version2.reduce(reduce);
}
버전 목록에서 최신 버전을 찾으려면 유용 할 수 있습니다.
function findLatestVersion(versions) {
if (!(versions instanceof Array)) {
versions = Array.prototype.slice.apply(arguments, [0]);
}
versions = versions.map(function(version) { return version.split('.'); });
var maxSubVersionLength = String(Math.max.apply(undefined, Array.prototype.concat.apply([], versions))).length;
var reduce = function(prev, current, index) {
return parseFloat(prev) + parseFloat('0.' + Array(index + (maxSubVersionLength - String(current).length)).join('0') + current);
};
var sums = [];
for (var i = 0; i < versions.length; i++) {
sums.push(parseFloat(versions[i].reduce(reduce)));
}
return versions[sums.indexOf(Math.max.apply(undefined, sums))].join('.');
}
console.log(findLatestVersion('0.1000000.1', '2.0.0.10', '1.6.10', '1.4.3', '2', '2.0.0.1')); // 2.0.0.10
console.log(findLatestVersion(['0.1000000.1', '2.0.0.10', '1.6.10', '1.4.3', '2', '2.0.0.1'])); // 2.0.0.10
재귀 알고리즘으로 수행하는 다른 방법이 있습니다.
이 코드는 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
이것은 질문에 대한 해결책이 아니지만 매우 유사합니다.
이런 종류의 기능을위한 의미 론적 버전 이 같은 와일드 카드와 함께 일을하지 않도록,이 버전을 해결 핸들 x
이나 *
.
이 정규식이 일치하는 버전에서 작동합니다 /\d+\.\d+\.\d+.*$/
. 이 답변 은와 같은 버전에서도 작동한다는 점을 제외하면 이 답변 과 매우 유사합니다 1.2.3-dev
. 다른 답변과 비교하여 : 필요하지 않은 일부 검사를 제거했지만 내 솔루션을 다른 솔루션과 결합 할 수 있습니다.
semVerSort = function(v1, v2) {
var v1Array = v1.split('.');
var v2Array = v2.split('.');
for (var i=0; i<v1Array.length; ++i) {
var a = v1Array[i];
var b = v2Array[i];
var aInt = parseInt(a, 10);
var bInt = parseInt(b, 10);
if (aInt === bInt) {
var aLex = a.substr((""+aInt).length);
var bLex = b.substr((""+bInt).length);
if (aLex === '' && bLex !== '') return 1;
if (aLex !== '' && bLex === '') return -1;
if (aLex !== '' && bLex !== '') return aLex > bLex ? 1 : -1;
continue;
} else if (aInt > bInt) {
return 1;
} else {
return -1;
}
}
return 0;
}
합병 된 해결책은 다음과 같습니다.
function versionCompare(v1, v2, options) {
var zeroExtend = options && options.zeroExtend,
v1parts = v1.split('.'),
v2parts = v2.split('.');
if (zeroExtend) {
while (v1parts.length < v2parts.length) v1parts.push("0");
while (v2parts.length < v1parts.length) v2parts.push("0");
}
for (var i = 0; i < v1parts.length; ++i) {
if (v2parts.length == i) {
return 1;
}
var v1Int = parseInt(v1parts[i], 10);
var v2Int = parseInt(v2parts[i], 10);
if (v1Int == v2Int) {
var v1Lex = v1parts[i].substr((""+v1Int).length);
var v2Lex = v2parts[i].substr((""+v2Int).length);
if (v1Lex === '' && v2Lex !== '') return 1;
if (v1Lex !== '' && v2Lex === '') return -1;
if (v1Lex !== '' && v2Lex !== '') return v1Lex > v2Lex ? 1 : -1;
continue;
}
else if (v1Int > v2Int) {
return 1;
}
else {
return -1;
}
}
if (v1parts.length != v2parts.length) {
return -1;
}
return 0;
}
'programing tip' 카테고리의 다른 글
JavaScript의 querySelector 및 querySelectorAll vs getElementsByClassName 및 getElementById (0) | 2020.06.16 |
---|---|
jquery : Enter 키를 누를 때 클릭 이벤트를 트리거하는 방법 (0) | 2020.06.16 |
파이썬에서 메소드 오버로딩을 어떻게 사용합니까? (0) | 2020.06.16 |
XElement의 InnerXml을 얻는 가장 좋은 방법은 무엇입니까? (0) | 2020.06.16 |
해시에서 키와 값 교환 (0) | 2020.06.16 |