mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
添加 Windows 资源管理器风格字符串比较器
This commit is contained in:
parent
5a2fe05346
commit
d897fced85
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024. looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* https://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.dromara.hutool.core.comparator;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Windows 资源管理器风格字符串比较器
|
||||||
|
*
|
||||||
|
* <p>此比较器模拟了 Windows 资源管理器的文件名排序方式,可得到与其相同的排序结果。</p>
|
||||||
|
*
|
||||||
|
* <p>假设有一个数组,包含若干个文件名 {@code {"abc2.doc", "abc1.doc", "abc12.doc"}}</p>
|
||||||
|
* <p>在 Windows 资源管理器中以名称排序时,得到 {@code {"abc1.doc", "abc2.doc", "abc12.doc" }}</p>
|
||||||
|
* <p>调用 {@code Arrays.sort(filenames);} 时,得到 {@code {"abc1.doc", "abc12.doc", "abc2.doc" }}</p>
|
||||||
|
* <p>调用 {@code Arrays.sort(filenames, new WindowsExplorerStringComparator());} 时,得到 {@code {"abc1.doc", "abc2.doc",
|
||||||
|
* "abc12.doc" }},这与在资源管理器中看到的相同</p>
|
||||||
|
*
|
||||||
|
* @author YMNNs
|
||||||
|
* @see
|
||||||
|
* <a href="https://stackoverflow.com/questions/23205020/java-sort-strings-like-windows-explorer">Java - Sort Strings like Windows Explorer</a>
|
||||||
|
*/
|
||||||
|
public class WindowsExplorerStringComparator implements Comparator<CharSequence> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单例
|
||||||
|
*/
|
||||||
|
public static final WindowsExplorerStringComparator INSTANCE = new WindowsExplorerStringComparator();
|
||||||
|
|
||||||
|
private static final Pattern splitPattern = Pattern.compile("\\d+|\\.|\\s");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(final CharSequence str1, final CharSequence str2) {
|
||||||
|
final Iterator<String> i1 = splitStringPreserveDelimiter(str1).iterator();
|
||||||
|
final Iterator<String> i2 = splitStringPreserveDelimiter(str2).iterator();
|
||||||
|
while (true) {
|
||||||
|
//Til here all is equal.
|
||||||
|
if (!i1.hasNext() && !i2.hasNext()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//first has no more parts -> comes first
|
||||||
|
if (!i1.hasNext()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
//first has more parts than i2 -> comes after
|
||||||
|
if (!i2.hasNext()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String data1 = i1.next();
|
||||||
|
final String data2 = i2.next();
|
||||||
|
int result;
|
||||||
|
try {
|
||||||
|
//If both data are numbers, then compare numbers
|
||||||
|
result = Long.compare(Long.parseLong(data1), Long.parseLong(data2));
|
||||||
|
//If numbers are equal than longer comes first
|
||||||
|
if (result == 0) {
|
||||||
|
result = -Integer.compare(data1.length(), data2.length());
|
||||||
|
}
|
||||||
|
} catch (final NumberFormatException ex) {
|
||||||
|
//compare text case insensitive
|
||||||
|
result = data1.compareToIgnoreCase(data2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> splitStringPreserveDelimiter(final CharSequence str) {
|
||||||
|
final Matcher matcher = splitPattern.matcher(str);
|
||||||
|
final List<String> list = new ArrayList<>();
|
||||||
|
int pos = 0;
|
||||||
|
while (matcher.find()) {
|
||||||
|
list.add(StrUtil.sub(str, pos, matcher.start()));
|
||||||
|
list.add(matcher.group());
|
||||||
|
pos = matcher.end();
|
||||||
|
}
|
||||||
|
list.add(StrUtil.subSuf(str, pos));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package org.dromara.hutool.core.comparator;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.collection.ListUtil;
|
||||||
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class WindowsExplorerStringComparatorTest {
|
||||||
|
|
||||||
|
final List<String> answer1 = ListUtil.of(
|
||||||
|
"filename",
|
||||||
|
"filename 00",
|
||||||
|
"filename 0",
|
||||||
|
"filename 01",
|
||||||
|
"filename.jpg",
|
||||||
|
"filename.txt",
|
||||||
|
"filename00.jpg",
|
||||||
|
"filename00a.jpg",
|
||||||
|
"filename00a.txt",
|
||||||
|
"filename0",
|
||||||
|
"filename0.jpg",
|
||||||
|
"filename0a.txt",
|
||||||
|
"filename0b.jpg",
|
||||||
|
"filename0b1.jpg",
|
||||||
|
"filename0b02.jpg",
|
||||||
|
"filename0c.jpg",
|
||||||
|
"filename01.0hjh45-test.txt",
|
||||||
|
"filename01.0hjh46",
|
||||||
|
"filename01.1hjh45.txt",
|
||||||
|
"filename01.hjh45.txt",
|
||||||
|
"Filename01.jpg",
|
||||||
|
"Filename1.jpg",
|
||||||
|
"filename2.hjh45.txt",
|
||||||
|
"filename2.jpg",
|
||||||
|
"filename03.jpg",
|
||||||
|
"filename3.jpg"
|
||||||
|
);
|
||||||
|
|
||||||
|
List<String> answer2 = ListUtil.of(
|
||||||
|
"abc1.doc",
|
||||||
|
"abc2.doc",
|
||||||
|
"abc12.doc"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompare1() {
|
||||||
|
final List<String> toSort = new ArrayList<>(answer1);
|
||||||
|
while (toSort.equals(answer1)) {
|
||||||
|
Collections.shuffle(toSort);
|
||||||
|
}
|
||||||
|
toSort.sort(WindowsExplorerStringComparator.INSTANCE);
|
||||||
|
Assert.equals(toSort, answer1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompare2() {
|
||||||
|
final List<String> toSort = new ArrayList<>(answer2);
|
||||||
|
while (toSort.equals(answer2)) {
|
||||||
|
Collections.shuffle(toSort);
|
||||||
|
}
|
||||||
|
toSort.sort(WindowsExplorerStringComparator.INSTANCE);
|
||||||
|
Assert.equals(toSort, answer2);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user