diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/comparator/VersionComparator.java b/hutool-core/src/main/java/org/dromara/hutool/core/comparator/VersionComparator.java index b232bdfe1..9486e8865 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/comparator/VersionComparator.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/comparator/VersionComparator.java @@ -13,15 +13,14 @@ package org.dromara.hutool.core.comparator; import org.dromara.hutool.core.convert.Convert; -import org.dromara.hutool.core.regex.PatternPool; +import org.dromara.hutool.core.math.NumberUtil; import org.dromara.hutool.core.regex.ReUtil; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.split.SplitUtil; -import org.dromara.hutool.core.util.ObjUtil; import java.io.Serializable; -import java.util.Comparator; import java.util.List; +import java.util.regex.Pattern; /** * 版本比较器
@@ -33,19 +32,34 @@ import java.util.List; * @author Looly * @since 4.0.2 */ -public class VersionComparator implements Comparator, Serializable { - private static final long serialVersionUID = 8083701245147495562L; +public class VersionComparator extends NullComparator implements Serializable { + private static final long serialVersionUID = 1L; - /** 单例 */ + private static Pattern PATTERN_PRE_NUMBERS= Pattern.compile("^\\d+"); + + /** + * 单例 + */ public static final VersionComparator INSTANCE = new VersionComparator(); /** * 默认构造 */ public VersionComparator() { + this(false); + } + + /** + * 默认构造 + * + * @param nullGreater 是否{@code null}最大,排在最后 + */ + public VersionComparator(final boolean nullGreater) { + super(nullGreater, (VersionComparator::compareVersion)); } // ----------------------------------------------------------------------------------------------------- + /** * 比较两个版本
* null版本排在最小:即: @@ -63,44 +77,35 @@ public class VersionComparator implements Comparator, Serializable { * @param version1 版本1 * @param version2 版本2 */ - @Override - public int compare(final String version1, final String version2) { - if(ObjUtil.equals(version1, version2)) { - return 0; - } - if (version1 == null && version2 == null) { - return 0; - } else if (version1 == null) {// null视为最小版本,排在前 - return -1; - } else if (version2 == null) { - return 1; - } - + private static int compareVersion(final String version1, final String version2) { final List v1s = SplitUtil.splitTrim(version1, StrUtil.DOT); final List v2s = SplitUtil.splitTrim(version2, StrUtil.DOT); int diff = 0; - final int minLength = Math.min(v1s.size(), v2s.size());// 取最小长度值 + final int minSize = Math.min(v1s.size(), v2s.size());// 取最小长度值 String v1; String v2; - for (int i = 0; i < minLength; i++) { + for (int i = 0; i < minSize; i++) { v1 = v1s.get(i); v2 = v2s.get(i); // 先比较长度 diff = v1.length() - v2.length(); if (0 == diff) { + // 长度相同,直接比较字符或数字 diff = v1.compareTo(v2); - }else { - // https://gitee.com/dromara/hutool/pulls/1043 - //不同长度的先比较前面的数字;前面数字不相等时,按数字大小比较;数字相等的时候,继续按长度比较, - final int v1Num = Convert.toInt(ReUtil.get(PatternPool.NUMBERS, v1, 0), 0); - final int v2Num = Convert.toInt(ReUtil.get(PatternPool.NUMBERS, v2, 0), 0); - final int diff1 = v1Num - v2Num; - if (diff1 != 0) { - diff = diff1; + } else { + // 不同长度,且含有字母 + if(!NumberUtil.isNumber(v1) || !NumberUtil.isNumber(v2)){ + //不同长度的先比较前面的数字;前面数字不相等时,按数字大小比较;数字相等的时候,继续按长度比较,类似于 103 > 102a + final int v1Num = Convert.toInt(ReUtil.get(PATTERN_PRE_NUMBERS, v1, 0), 0); + final int v2Num = Convert.toInt(ReUtil.get(PATTERN_PRE_NUMBERS, v2, 0), 0); + final int diff1 = v1Num - v2Num; + if (diff1 != 0) { + diff = diff1; + } } } - if(diff != 0) { + if (diff != 0) { //已有结果,结束 break; } diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/comparator/IssueI81N3HTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/comparator/IssueI81N3HTest.java new file mode 100644 index 000000000..c24863d9d --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/comparator/IssueI81N3HTest.java @@ -0,0 +1,18 @@ +package org.dromara.hutool.core.comparator; + +import org.dromara.hutool.core.collection.ListUtil; +import org.dromara.hutool.core.io.IoUtil; +import org.dromara.hutool.core.io.resource.ResourceUtil; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +public class IssueI81N3HTest { + + @Test + void sortTest() { + final List list = IoUtil.readUtf8Lines(ResourceUtil.getStream("IssueI81N3H.list"), new ArrayList<>()); + ListUtil.sort(list, VersionComparator.INSTANCE.reversed()); + } +} diff --git a/hutool-core/src/test/resources/IssueI81N3H.list b/hutool-core/src/test/resources/IssueI81N3H.list new file mode 100644 index 000000000..45bd3d34a --- /dev/null +++ b/hutool-core/src/test/resources/IssueI81N3H.list @@ -0,0 +1,257 @@ +remotes/origin/Foldn-dev +remotes/origin/HEAD -> origin/dev +remotes/origin/HOTFIX-20230519 +remotes/origin/HOTFIX-20230703 +remotes/origin/HOTFIX-20230705 +remotes/origin/HOTFIX-20230705(1) +remotes/origin/HOTFIX-20230810 +remotes/origin/HOTFIX-20230811 +remotes/origin/HOTFIX-20230825 +remotes/origin/HOTFIX-337-20230517 +remotes/origin/HOTFIX-436 +remotes/origin/HOTFIX-458 +remotes/origin/HOTFIX-521 +remotes/origin/HOTFIX-ESString +remotes/origin/HOTFIX-JDEV-851 +remotes/origin/HOTFIX-JDEV-856 +remotes/origin/HOTFIX-JDEV-978 +remotes/origin/HOTFIX-LOG +remotes/origin/HOTFIX-NEWREQUIRE-216 +remotes/origin/HOTFIX-remind +remotes/origin/HOTFIX-webOfficeURL +remotes/origin/HOTFiX-20230523(contractNo) +remotes/origin/JDEV-852 +remotes/origin/Jarvis-20230131 +remotes/origin/Jarvis-20230320 +remotes/origin/Jarvis-20230322 +remotes/origin/Jarvis-20230525 +remotes/origin/Jarvis-20230526 +remotes/origin/Jarvis-20230817 +remotes/origin/Jarvis-20230830 +remotes/origin/Jarvis-20230913 +remotes/origin/Jarvis-Release +remotes/origin/Jarvis-kinglex +remotes/origin/JarvisCaseInsert-20230525 +remotes/origin/JarvisCaseList-20230803 +remotes/origin/JarvisMemberTwo-20230821 +remotes/origin/JarvisNotice-20230322 +remotes/origin/JarvisNoticeAndCustomer-20230728 +remotes/origin/JarvisNoticeRelease-20230519 +remotes/origin/JarvisTeamInvisible-20230427 +remotes/origin/Jarvis_dev +remotes/origin/Jarvisdev-20230322 +remotes/origin/Jerry-dev +remotes/origin/KAPP-20230227-936 +remotes/origin/KDOC-511 +remotes/origin/Leon-dev +remotes/origin/Lester_dev +remotes/origin/Linkin-1 +remotes/origin/Linkin-dev +remotes/origin/NEWREQUIRE-157 +remotes/origin/NEWREQUIRE-200(20230523) +remotes/origin/NEWREQUIRE-20230227-147 +remotes/origin/NEWREQUIRE-20230303-135 +remotes/origin/NEWREQUIRE-216 +remotes/origin/NEWREQUIRE-247 +remotes/origin/app +remotes/origin/dev +remotes/origin/dev-202303 +remotes/origin/dev-202303-01 +remotes/origin/dev-202303-02 +remotes/origin/dev-202303-03 +remotes/origin/doc +remotes/origin/fearture-20230321-vas +remotes/origin/featrues-200 +remotes/origin/featrues-appDeletion +remotes/origin/featrues-dingding +remotes/origin/featrues-ftsDownZip +remotes/origin/featrues-newDataSync +remotes/origin/featrues-switchByUI +remotes/origin/featrues-webOffice +remotes/origin/featrues-wk +remotes/origin/feature-add-trace-id +remotes/origin/feature-config-use-nacos +remotes/origin/feature-doc-20230308 +remotes/origin/feature-lester-20230414 +remotes/origin/feature-va-invoice-lester +remotes/origin/features-alertModify +remotes/origin/features-appComprehensive +remotes/origin/features-comprehensive +remotes/origin/features-finance +remotes/origin/features-getNewId +remotes/origin/features-homeController +remotes/origin/features-pushMessage +remotes/origin/features-revenue-expenditure +remotes/origin/hotfix-20220704 +remotes/origin/hotfix-20220823 +remotes/origin/hotfix-20220908 +remotes/origin/hotfix-20220917 +remotes/origin/hotfix-20220919 +remotes/origin/hotfix-20220927 +remotes/origin/hotfix-20221021 +remotes/origin/hotfix-20221102-docPreview +remotes/origin/hotfix-20221103 +remotes/origin/hotfix-20221104 +remotes/origin/hotfix-20221104-bug +remotes/origin/hotfix-20221107 +remotes/origin/hotfix-20221108 +remotes/origin/hotfix-20221109-docScope +remotes/origin/hotfix-20221110 +remotes/origin/hotfix-20221111 +remotes/origin/hotfix-20221111-ossupload +remotes/origin/hotfix-20221114 +remotes/origin/hotfix-20221115 +remotes/origin/hotfix-20221116 +remotes/origin/hotfix-20221116-bug +remotes/origin/hotfix-20221118 +remotes/origin/hotfix-20221119 +remotes/origin/hotfix-20221121 +remotes/origin/hotfix-20221121-fts +remotes/origin/hotfix-20221122-bug +remotes/origin/hotfix-20221124-bug +remotes/origin/hotfix-20221201 +remotes/origin/hotfix-20221201-bug +remotes/origin/hotfix-20221203 +remotes/origin/hotfix-20221212 +remotes/origin/hotfix-20230104 +remotes/origin/hotfix-20230208 +remotes/origin/hotfix-20230213 +remotes/origin/hotfix-20230215 +remotes/origin/hotfix-20230221-fts +remotes/origin/hotfix-20230302-fileUpLoad +remotes/origin/hotfix-20230307-doc +remotes/origin/hotfix-20230314 +remotes/origin/hotfix-20230315-mail +remotes/origin/hotfix-20230321-wpslog +remotes/origin/hotfix-20230322 +remotes/origin/hotfix-20230322-bill +remotes/origin/hotfix-20230323 +remotes/origin/hotfix-20230327 +remotes/origin/hotfix-20230331 +remotes/origin/hotfix-20230331-blankdoc +remotes/origin/hotfix-20230410 +remotes/origin/hotfix-20230413 +remotes/origin/hotfix-20230417 +remotes/origin/hotfix-20230428 +remotes/origin/hotfix-20230508 +remotes/origin/hotfix-20230515 +remotes/origin/hotfix-20230515-FINANCE-1294 +remotes/origin/hotfix-20230516-FINANCE-1299 +remotes/origin/hotfix-20230519 +remotes/origin/hotfix-20230519-1256 +remotes/origin/hotfix-20230524-FINANCE-1300 +remotes/origin/hotfix-20230524-FINANCE-1352 +remotes/origin/hotfix-20230524-FINANCE-1365 +remotes/origin/hotfix-20230529-FINANCE-1409 +remotes/origin/hotfix-20230531 +remotes/origin/hotfix-20230603 +remotes/origin/hotfix-20230607 +remotes/origin/hotfix-20230617-INVANTORY-1466 +remotes/origin/hotfix-20230707 +remotes/origin/hotfix-20230710 +remotes/origin/hotfix-20230713-inventory +remotes/origin/hotfix-20230720 +remotes/origin/hotfix-20230722 +remotes/origin/hotfix-20230724 +remotes/origin/hotfix-20230726 +remotes/origin/hotfix-20230727 +remotes/origin/hotfix-20230731 +remotes/origin/hotfix-20230803 +remotes/origin/hotfix-20230804 +remotes/origin/hotfix-20230805 +remotes/origin/hotfix-20230817 +remotes/origin/hotfix-20230817-INV-1307 +remotes/origin/hotfix-20230817-INV-1492 +remotes/origin/hotfix-20230818-INV-1353 +remotes/origin/hotfix-20230831-INV-1531 +remotes/origin/hotfix-leon-20230613 +remotes/origin/hotfix-leon-20230626 +remotes/origin/hotfix-leon-20230628 +remotes/origin/hotfix-leon-20230717 +remotes/origin/hotfix-leon-20230724 +remotes/origin/hotfix-leon-20230727 +remotes/origin/hotfix-lester-20230302 +remotes/origin/hotfix-lester-20230303 +remotes/origin/hotfix-lester-20230317 +remotes/origin/hotfix-lester-20230417 +remotes/origin/hotfix-remind +remotes/origin/hotfix20230614 +remotes/origin/hoxfix-20220926 +remotes/origin/hoxfix-20221102-bug +remotes/origin/huashang +remotes/origin/insertField +remotes/origin/inventory +remotes/origin/inventory-auto +remotes/origin/inventory-bak-20230630-dev +remotes/origin/inventory-bak-20230630-release +remotes/origin/inventory-chaos +remotes/origin/inventory-chaos-20230704-release-2 +remotes/origin/inventory-fee +remotes/origin/inventory-merge +remotes/origin/inventory-release-1 +remotes/origin/inventory-rpc-20230727 +remotes/origin/inventory-task +remotes/origin/jarvis-20230306 +remotes/origin/jarvis-qiyuesuo +remotes/origin/jarvisAppFile-20230802 +remotes/origin/lester-2023-0109 +remotes/origin/lester-2023-0524 +remotes/origin/lester-2023-0525 +remotes/origin/lester-2023-0529 +remotes/origin/lester-2023-0530 +remotes/origin/lester-2023-0601 +remotes/origin/lester-2023-0620 +remotes/origin/lester-2023-0705 +remotes/origin/lester-20230311 +remotes/origin/lester-20230315 +remotes/origin/lester-20230406 +remotes/origin/lester-20230727 +remotes/origin/lester-HOTFIX-497 +remotes/origin/lester-JDEV-844 +remotes/origin/lester-blue-hotfix +remotes/origin/lester-dev +remotes/origin/lester-dev-20230311 +remotes/origin/lester-hotfix-0714 +remotes/origin/lester-hotfix-0719-2 +remotes/origin/lester-hotfix-20230711 +remotes/origin/lester-hotfix-20230712 +remotes/origin/lester-hotfix-20230713 +remotes/origin/lester-hotfix-20230714 +remotes/origin/lester-hotfix-20230717 +remotes/origin/lester-hotfix-20230718 +remotes/origin/lester-hotfix-20230718-1 +remotes/origin/lester-hotfix-20230719 +remotes/origin/lester-hotfix-20230721 +remotes/origin/lester-hotfix-20230724 +remotes/origin/lester-hotfix-20230728 +remotes/origin/lester-hotfix-202308002-1 +remotes/origin/lester-hotfix-20230802 +remotes/origin/lester-hotfix-20230803 +remotes/origin/lester-hotfix-20230804 +remotes/origin/lester-hotfix-20230807-01 +remotes/origin/lester-hotfix-20230807-02 +remotes/origin/lester-hotfix-20230809 +remotes/origin/lester-hotfix-20230810 +remotes/origin/lester-hotfix-20230811 +remotes/origin/lester-hotfix-20230814 +remotes/origin/lester-hotfix-20230911 +remotes/origin/lester-hotfix-JDEV-864 +remotes/origin/lester-hotfix-workflow-0711 +remotes/origin/lester-invoice-dev +remotes/origin/lester-invoice-release +remotes/origin/lester-workHours +remotes/origin/login-register +remotes/origin/newRequire-20230110 +remotes/origin/newrequire-20230216 +remotes/origin/newrequire-20230529-FINANCE-1308 +remotes/origin/openapi +remotes/origin/pay-20220921 +remotes/origin/pc-login +remotes/origin/pety +remotes/origin/pre-dev-inventoryAuto +remotes/origin/pre-release-inventoryAuto +remotes/origin/release +remotes/origin/release-backup-2023-07-06 +remotes/origin/va_dev +remotes/origin/workToolDataSync +remotes/origin/zoran