연관문제: 버전비교
원문: Semantic Versioning 2.0.0, (한글번역) 유의적 버전 2.0.0
이 라이센스 를 표기해줘야 한답니다.
소프트웨어 버전들을 입력 받아, 우선순위가 높은 순서로 출력하시오.
위 글에서 형식 부분만 정리했습니다.
예) 0.1.0, 1.5.0, 4.12.2
X.Y.Z 로 표기한다. X, Y, Z 모두 0 이상의 정수이다.
0을 앞에 붙이지 않는다 (예: 1.03.0 (X), 1.3.0 (O))
예) 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92
X.Y.Z 뒤에 붙임표 "-"를 넣고, 마침표 "."로 구분된 1개 이상의 식별자(id)를 붙인다.
식별자(id)는 한 글자 이상이다(예: 1.0.0-1..1 (X), 1.0.0-1.0.1 (O))
식별자(id)는 반드시 아스키(ASCII) 문자, 숫자, 붙임표로만 구성한다: [0-9A-Za-z-]
숫자 식별자 앞에 0을 붙이지 않는다.
예) 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85
X.Y.Z 뒤, 또는 pre-release 버전의 뒤에 "+"를 넣고, ,마침표(".")로 구분된 1개 이상의 식별자(id)를 붙인다.
식별자(id) 작성 규칙은 pre-release 버전에 기술한 바와 같다.
식별자를 차례로 비교해서 다른 부분이 나타나면 우선순위가 결정된다.
숫자로만 구성된 식별자는 수의 크기로 비교하고,
알파벳이나 붙임표 "-" 가 포함된 경우에는 아스키 문자열 정렬을 한다.
(사전 순서를 의미하는 듯함)
1) X.Y.Z 에서 X, Y, Z 를 차례로, 숫자로서 비교한다.
1.0.0 < 2.0.0 < 2.1.0 < 2.1.1
마침표 "." 는 소수점이 아님을 주의하라. 아래의 예에서 비교 순서는 1 == 1 그리고 5 < 12 이다.
1.5.0 < 1.12.0
2). X.Y.Z 가 같으면 pre-release 버전의 우선순위가 더 낮다.
1.0.0-alpha < 1.0.0
3) 숫자로만 구성된 식별자는 그렇지 않은 식별자보다 우선순위가 무조건 더 낮다.
1.0.0-10 < 1.0.0-alpha
4) 빌드 메타데이터는 버전 우선순위에 영향이 없다.
아래 두 버전의 우선순위는 같다.
1.0.0-alpha+001, 1.0.0-alpha+exp.sha.5114f85
5) pre-release 버전에서 앞선 식별자가 모두 같으면 필드 수가 많은 쪽의 우선순위가 더 높다.
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
우선순위가 높은 순서대로 출력한다.
우선순위가 같으면 전체 길이가 긴 버전을 먼저 출력한다.
1.2.0
1.0.0-beta+exp.sha.5114f85
1.12.0
1.0.0-beta.1.2
1.0.0-alpha
1.0.0-rc.1
1.0.0-rc.2
1.2.1
1.0.0-beta.2
1.0.0
1.10.0
1.0.0+20130313144700
1.0.0-alpha.beta
1.0.0-10
1.5.0
1.0.0-beta.11
1.0.0-alpha.1
1.0.0-alpha+001
1.0.0-beta.1
빈 줄은 보기 편하도록 넣었으니 실제 출력할 때는 없어도 관계없습니다.
1.12.0
1.10.0
1.5.0
1.2.1
1.2.0
1.0.0+20130313144700
1.0.0
1.0.0-rc.2
1.0.0-rc.1
1.0.0-beta.11
1.0.0-beta.2
1.0.0-beta.1.2
1.0.0-beta.1
1.0.0-beta+exp.sha.5114f85
1.0.0-alpha.beta
1.0.0-alpha.1
1.0.0-alpha+001
1.0.0-alpha
1.0.0-10
2개의 풀이가 있습니다.
def ver(x):
length = len(x)
m = x.find('+')
if m > -1: x = x[:m]
p = x.find('-')
if p == -1:
return [[int(i) for i in x.split('.')], 1, length]
else:
pre = x[p+1:].split('.')
tmp = max(len(i) for i in pre)
return [[*map(int, x[:p].split('.'))], 0, [i.zfill(tmp) if i.isdigit() else i for i in pre], length]
test = '''\
1.2.0
1.0.0-beta+exp.sha.5114f85
1.12.0
1.0.0-beta.1.2
1.0.0-alpha
1.0.0-rc.1
1.0.0-rc.2
1.2.1
1.0.0-beta.2
1.0.0
1.10.0
1.0.0+20130313144700
1.0.0-alpha.beta
1.0.0-10
1.5.0
1.0.0-beta.11
1.0.0-alpha.1
1.0.0-alpha+001
1.0.0-beta.1'''
test = [i.strip() for i in test.splitlines()]
for i in sorted(test, key=ver, reverse=True): print(i)
1.12.0
1.10.0
1.5.0
1.2.1
1.2.0
1.0.0+20130313144700
1.0.0
1.0.0-rc.2
1.0.0-rc.1
1.0.0-beta.11
1.0.0-beta.2
1.0.0-beta.1.2
1.0.0-beta.1
1.0.0-beta+exp.sha.5114f85
1.0.0-alpha.beta
1.0.0-alpha.1
1.0.0-alpha+001
1.0.0-alpha
1.0.0-10
# 유효성 검사는 하지 않는다.
class Identifier(str):
def __lt__(self, other):
if self.isdigit() and other.isdigit():
return int(self) < int(other)
else:
return str(self) < str(other)
class Version(str):
def __init__(self, src):
super().__init__()
self.rel, self.pre = [], []
if '+' in src:
src = src[:src.index('+')]
if '-' in src:
i = src.index('-')
self.pre = [Identifier(x) for x in src[i + 1:].split('.')]
src = src[:i]
self.rel = [Identifier(x) for x in src.split('.')]
def __lt__(self, other):
if self.rel != other.rel:
return self.rel < other.rel
else:
# X.Y.Z 같음
if not self.pre and not other.pre:
return len(self) < len(other) # release X 2
elif bool(self.pre) != bool(other.pre):
return bool(self.pre) # pre-relese, release
else:
# pre-release X 2
if self.pre == other.pre:
return len(self) < len(other)
else:
return self.pre < other.pre
versions = [Version(x) for x in inp_str.split('\n')]
print('\n'.join(sorted(versions, reverse=True)))