目录
- 前言
- 1. 基本知识
- 2. 实战
前言
#1024程序员节 | 征文#
对于Java的基本知识推荐阅读:
- java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
- 【Java项目】实战CRUD的功能整理(持续更新)
原先的Java中文排序,推荐阅读:Java或者前端 实现中文排序(调API的Demo)
以下文章主要记录自定义实战的中文排序
1. 基本知识
在Java中,中文排序通常涉及到使用Collator类来处理字符串的比较,确保根据汉字的拼音顺序进行排序
以下是详细分析和示例代码:(上述链接文章已经说清楚了,但先讲解一遍浅显的知识)
- Collator类:用于比较字符串,特别适用于处理不同语言的排序
- Locale:指定语言环境,影响排序规则
- compare方法:用于比较两个字符串,根据指定的语言环境返回排序结果
示例代码如下:
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
public class ChineseSortingDemo {
public static void main(String[] args) {
// 创建一个包含中文字符串的列表
List<String> chineseNames = new ArrayList<>();
chineseNames.add("张三");
chineseNames.add("李四");
chineseNames.add("王五");
chineseNames.add("赵六");
// 获取中文排序的Collator实例
Collator collator = Collator.getInstance(Locale.CHINESE);
// 对列表进行排序
Collections.sort(chineseNames, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return collator.compare(o1, o2); // 使用Collator比较
}
});
// 输出排序后的结果
System.out.println("排序后的中文名字:");
for (String name : chineseNames) {
System.out.println(name);
}
}
}
基本的逻辑如下:
- 导入所需类:导入Collator、ArrayList、Collections、Comparator和Locale
- 创建列表:使用ArrayList来存储中文字符串
- 获取Collator实例:使用Collator.getInstance(Locale.CHINESE)来获取适用于中文的排序规则
- 排序操作:通过Collections.sort()和自定义比较器,使用collator.compare()进行排序
2. 实战
自定义中文排序通常涉及对字符串的特定部分进行比较,以满足业务需求
主要目标是按照特定的中文数字(如“一”、“二”等)和名称排序,逻辑如下
- 提取数字部分:通过extractChineseNumber方法,从每个字符串中提取汉字数字部分。如果字符串包含汉字数字,则优先根据这些数字排序
- 排序优先级:首先,包含“类”的项优先。其次,根据提取的汉字数字进行排序,使用自定义比较器来定义排序规则。
最后,对于没有数字的项,按字典顺序排序 - 使用流式处理:通过Java 8的流式API进行排序,增强代码的可读性和简洁性
注意事项
- 字符集:确保输入的字符串都为标准汉字,避免因字符集不同导致的排序错误
- 性能:在处理大量数据时,排序操作可能会影响性能,尽量优化提取逻辑
- 多样性:考虑到可能存在的多种中文数字(如“零”)和不同的业务需求,确保排序规则的灵活性
- 边界情况:处理字符串中可能没有汉字数字的情况,避免空指针异常
// 查询所有数据,不进行分页
List<Sort> allRecords = sortService.list(queryWrapper);
// 自定义中文数字排序规则
Comparator<String> chineseNumberComparator = (a, b) -> {
String[] chineseNumbers = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十"};
List<String> chineseNumberList = Arrays.asList(chineseNumbers);
// 获取字符串的汉字数字部分
String aNumberPart = extractChineseNumber(a);
String bNumberPart = extractChineseNumber(b);
// 如果都包含汉字数字部分,则按自定义顺序排序
if (chineseNumberList.contains(aNumberPart) && chineseNumberList.contains(bNumberPart)) {
return Integer.compare(chineseNumberList.indexOf(aNumberPart), chineseNumberList.indexOf(bNumberPart));
}
// 如果只有一个包含汉字数字,优先含有数字的排序
else if (chineseNumberList.contains(aNumberPart)) {
return -1;
} else if (chineseNumberList.contains(bNumberPart)) {
return 1;
}
// 如果都不包含汉字数字,则按字典序排序
return a.compareTo(b);
};
// 对所有记录进行排序
List<Sort> sortedRecords = allRecords.stream()
.sorted(Comparator.comparing((Sort record) -> {
String sortNameRecord = record.getSortName();
// 首先检查是否包含“类”,并提取类的前缀
boolean hasClass = sortNameRecord.contains("类");
// 确保包含“类”的项优先
return hasClass ? 0 : 1; // 优先级
})
.thenComparing(Comparator.comparing((Sort record) -> {
String sortNameRecord = record.getSortName();
// 如果包含“类”,提取汉字数字部分并按其索引排序
if (sortNameRecord.contains("类")) {
return extractChineseNumber(sortNameRecord); // 提取汉字数字部分
}
return ""; // 没有类的项返回空字符串以放置在最后
}, chineseNumberComparator)) // 按汉字数字排序
.thenComparing(Comparator.comparing(Sort::getSortName)) // 按名称进行自然排序
)
.collect(Collectors.toList());
/**
* 提取字符串中的汉字数字部分
*/
private String extractChineseNumber(String str) {
String[] chineseNumbers = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十"};
for (String number : chineseNumbers) {
if (str.contains(number)) {
return number;
}
}
return ""; // 如果没有汉字数字,返回空字符串
}
截图如下:
最终效果如下:
测试的总体Demo如下:
import java.util.*;
import java.util.stream.Collectors;
public class CustomChineseSorting {
public static void main(String[] args) {
List<Sort> allRecords = sortService.list(queryWrapper);
// 自定义中文数字排序规则
Comparator<String> chineseNumberComparator = (a, b) -> {
String[] chineseNumbers = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "零"};
List<String> chineseNumberList = Arrays.asList(chineseNumbers);
String aNumberPart = extractChineseNumber(a);
String bNumberPart = extractChineseNumber(b);
if (chineseNumberList.contains(aNumberPart) && chineseNumberList.contains(bNumberPart)) {
return Integer.compare(chineseNumberList.indexOf(aNumberPart), chineseNumberList.indexOf(bNumberPart));
} else if (chineseNumberList.contains(aNumberPart)) {
return -1;
} else if (chineseNumberList.contains(bNumberPart)) {
return 1;
}
return a.compareTo(b);
};
// 对所有记录进行排序
List<Sort> sortedRecords = allRecords.stream()
.sorted(Comparator.comparing((Sort record) -> {
String sortNameRecord = record.getSortName();
return sortNameRecord.contains("类") ? 0 : 1;
})
.thenComparing(Comparator.comparing((Sort record) -> {
String sortNameRecord = record.getSortName();
if (sortNameRecord.contains("类")) {
return extractChineseNumber(sortNameRecord);
}
return "";
}, chineseNumberComparator))
.thenComparing(Comparator.comparing(Sort::getSortName))
)
.collect(Collectors.toList());
// 输出排序后的结果
sortedRecords.forEach(record -> System.out.println(record.getSortName()));
}
// 提取字符串中的汉字数字部分
private static String extractChineseNumber(String str) {
String[] chineseNumbers = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"};
for (String number : chineseNumbers) {
if (str.contains(number)) {
return number;
}
}
return "";
}
}
主要的注意事项如下:
- 处理多个汉字数字:
若需要处理更大的数字(如“十一”、“十二”等),可进一步扩展extractChineseNumber方法,以支持更复杂的模式 - 兼容性排序:
可以考虑为英文字符或其他语言字符设置不同的排序逻辑,以满足多语言应用的需求 - 负数处理:
如果存在负数表示,可以在提取汉字数字时加入相关逻辑