Я хочу написать cmp
-like функцию , которая сравнивает два номера версии и возвращается -1
, 0
или на 1
основе их сравнении valuses.
- Вернуть,
-1
если версия A старше версии B - Вернуть,
0
если версии A и B эквивалентны - Вернуть,
1
если версия A новее, чем версия B
Предполагается, что каждый подраздел следует интерпретировать как число, поэтому 1.10> 1.1.
Желаемые функциональные выходы:
mycmp('1.0', '1') == 0
mycmp('1.0.0', '1') == 0
mycmp('1', '1.0.0.1') == -1
mycmp('12.10', '11.0.0.0.0') == 1
...
И вот моя реализация, открытая для улучшения:
def mycmp(version1, version2):
parts1 = [int(x) for x in version1.split('.')]
parts2 = [int(x) for x in version2.split('.')]
# fill up the shorter version with zeros ...
lendiff = len(parts1) - len(parts2)
if lendiff > 0:
parts2.extend([0] * lendiff)
elif lendiff < 0:
parts1.extend([0] * (-lendiff))
for i, p in enumerate(parts1):
ret = cmp(p, parts2[i])
if ret: return ret
return 0
Кстати, я использую Python 2.4.5. (установлен на моем рабочем месте ...).
Вот небольшой набор тестов, который вы можете использовать
assert mycmp('1', '2') == -1
assert mycmp('2', '1') == 1
assert mycmp('1', '1') == 0
assert mycmp('1.0', '1') == 0
assert mycmp('1', '1.000') == 0
assert mycmp('12.01', '12.1') == 0
assert mycmp('13.0.1', '13.00.02') == -1
assert mycmp('1.1.1.1', '1.1.1.1') == 0
assert mycmp('1.1.1.2', '1.1.1.1') == 1
assert mycmp('1.1.3', '1.1.3.000') == 0
assert mycmp('3.1.1.0', '3.1.2.10') == -1
assert mycmp('1.1', '1.10') == -1
python
string-comparison
Йоханнес Чарра
источник
источник
Ответы:
Удалите неинтересную часть строки (завершающие нули и точки), а затем сравните списки чисел.
Это тот же подход, что и Pär Wieslander, но немного более компактный:
Вот несколько тестов, благодаря « Как сравнить две строки в формате версии, разделенной точкой в Bash? »:
источник
rstrip(".0")
поменяется с ".10" на ".1" в "1.0.10".Как насчет использования Python
distutils.version.StrictVersion
?Итак, для вашей
cmp
функции:Если вы хотите сравнить более сложные номера версий, вам
distutils.version.LooseVersion
будет полезнее сравнивать только те же типы.LooseVersion
не самый умный инструмент, и его легко обмануть:Чтобы добиться успеха с этой породой, вам нужно выйти за рамки стандартной библиотеки и использовать утилиту синтаксического анализа setuptools
parse_version
.Таким образом, в зависимости от вашего конкретного варианта использования вам необходимо решить, достаточно ли встроенных
distutils
инструментов или необходимо добавить их в качестве зависимостиsetuptools
.источник
StrictVersion
ТОЛЬКО с версией с тремя номерами. Он не подходит для таких вещей, как0.4.3.6
!distribute
в этом ответе следует заменить наsetuptools
, который идет в комплекте сpkg_resources
пакетом и с тех пор ... как никогда . Точно так же это официальная документация дляpkg_resources.parse_version()
функции, входящей в комплектsetuptools
.Считается ли повторное использование элегантностью в данном случае? :)
источник
pkg_resources
этоsetuptools
упакованный пакет. Посколькуsetuptools
фактически является обязательным для всех установок Python,pkg_resources
он фактически доступен везде. Тем не менее,distutils.version
подпакет также полезен, хотя и значительно менее интеллектуален, чемpkg_resources.parse_version()
функция более высокого уровня . То, что вам следует использовать, зависит от того, какую степень безумия вы ожидаете в строках версии.setuptools
выходящим за рамки стандартной библиотеки, а вместо этого с моим заявленным предпочтениемdistutils
в данном случае . Итак, что именно вы имеете в виду под «фактически обязательным», и не могли бы вы представить доказательства того, что он был «фактически обязательным» 4,5 года назад, когда я написал этот комментарий?Нет необходимости перебирать кортежи версий. Встроенный оператор сравнения списков и кортежей уже работает точно так, как вы этого хотите. Вам просто нужно расширить списки версий до соответствующей длины. В python 2.6 вы можете использовать izip_longest для заполнения последовательностей.
В более ранних версиях требуется взлом карты.
источник
Это немного компактнее, чем ваше предложение. Вместо того, чтобы заполнять более короткую версию нулями, я удаляю конечные нули из списков версий после разделения.
источник
mycmp
для других целей в своем коде, если он вам понадобится.Удалите трейлинг
.0
и.00
с помощью регулярного выраженияsplit
и используйтеcmp
функцию, которая правильно сравнивает массивы:И, конечно, вы можете преобразовать его в однострочник, если не возражаете против длинных строк.
источник
Это однострочный (разделенный для удобочитаемости). Не уверен в удобочитаемости ...
источник
tuple
кстати, это не нужно):cmp(*zip(*map(lambda x,y:(x or 0,y or 0), map(int,v1.split('.')), map(int,v2.split('.')) )))
Реализован для php
version_compare
, кроме "=". Потому что это неоднозначно.источник
Списки сопоставимы в Python, поэтому, если кто-то преобразует строки, представляющие числа, в целые числа, можно с успехом использовать базовое сравнение Python.
Мне нужно было немного расширить этот подход, потому что я использую Python3x, где
cmp
функция больше не существует. Я должен был подражатьcmp(a,b)
с(a > b) - (a < b)
. Кроме того, номера версий не такие уж чистые и могут содержать всевозможные другие буквенно-цифровые символы. Бывают случаи, когда функция не может определить порядок, поэтому возвращаетсяFalse
(см. Первый пример).Я отправляю это, даже если вопрос старый и на него уже дан ответ, потому что это может сэкономить несколько минут в чьей-то жизни.
источник
Если вы не хотите использовать внешнюю зависимость, вот моя попытка, написанная для Python 3.x.
rc
,rel
(и, возможно, можно было бы добавитьc
), рассматриваются как «кандидат на выпуск» и делят номер версии на две части, а в случае отсутствия значение второй части высокое (999). Остальные буквы производят разделение и обрабатываются как субчисла через код base-36.источник
Самое трудное для чтения решение, но все же однострочное! и использовать итераторы для быстрой работы.
это для Python2.6 и 3. + btw, Python 2.5 и старше должны улавливать StopIteration.
источник
Я сделал это, чтобы иметь возможность анализировать и сравнивать строку версии пакета Debian. Обратите внимание, что проверка символов не является строгой.
Это также может быть полезно:
источник
Другое решение:
Можно использовать и так:
источник
Я использую это в своем проекте:
источник
Спустя годы, но этот вопрос все еще остается на первом месте.
Вот моя функция сортировки версий. Он разбивает версию на числовые и не числовые разделы. Числа сравниваются как
int
остальныеstr
(как части элементов списка).Вы можете использовать функцию
key
как своего рода настраиваемыйVersion
тип с операторами сравнения. Если вы действительно хотите использовать,cmp
вы можете сделать это, как в этом примере: https://stackoverflow.com/a/22490617/9935708Набор тестов пройден.
источник
Мое предпочтительное решение:
Добавление в строку дополнительных нулей и простое использование четырех первых легко понять, не требует никакого регулярного выражения, а лямбда более или менее читается. Я использую две строки для удобства чтения, для меня элегантность коротка и проста.
источник
Это мое решение (написано на C, извините). Я надеюсь ты сочтёшь это полезным
источник