前言:
目前看官们对“java字符数字排序”大致比较注重,我们都需要剖析一些“java字符数字排序”的相关知识。那么小编在网络上收集了一些关于“java字符数字排序””的相关资讯,希望姐妹们能喜欢,看官们快快来了解一下吧!我们在日常的开发中,偶尔会遇到这么一种场景,那就是对携带中文数字的字符串进行排序的问题,比如:“XXX号楼XX单元XXX号”等。说实话,作为一个懒人而言,寻找成熟的工具类是最快捷和省事的方法。但是我查了很久,都未发现可用的工具类。虽然在CSDN或博客园有人分享过类似的写法,但是测试之后总是觉得不尽如人意。思量再三后,还是决定自己实现。
其实仔细想想,排序这个事也没那么难。最重要的是想明白按照哪种规则进行排序即可。我想出的规则如下:
首先建立转换的字典表,也就是常见数字、单位与对应阿拉伯数字的映射关系。比较的时候通过两个索引来从前往后依次比较对应索引处的字符,若相等,则继续进行下一位的比较。当对应索引处的字符不相等时,则判断是否为数字,如果是则各自向前推进,直到遇到非数字为止,接着将获取到的字符串数字转换为Long类型后进行比较。若判断是字母,则直接进行比较。若判断为字典表中的值,则各自向前推进,直到遇到非字典中的值后,将获取到的字符串转换为Long类型后进行比较。若3,4,5三种情况都不满足,则按照默认的中文排序。
下面开始对应的代码实现。
建立转换的字典表
下面是建立字典表的代码:
private static Set<Character> keyList = new HashSet<>(); private static Map<Character, Long> basicNumMap = new HashMap<>(); private static Map<Character, Long> unitMap = new HashMap<>(); private static Map<Character, Long> bigUnitMap = new HashMap<>(); static { // 初始化basicNumMap basicNumMap.put('零', 0L); basicNumMap.put('一', 1L); basicNumMap.put('二', 2L); basicNumMap.put('三', 3L); basicNumMap.put('四', 4L); basicNumMap.put('五', 5L); basicNumMap.put('六', 6L); basicNumMap.put('七', 7L); basicNumMap.put('八', 8L); basicNumMap.put('九', 9L); // 初始化unitMap unitMap.put('十', 10L); unitMap.put('百', 100L); unitMap.put('千', 1000L); // 初始化unitMap bigUnitMap.put('万', 10000L); bigUnitMap.put('亿', 1_0000_0000L); // 初始化keyList keyList.addAll(basicNumMap.keySet()); keyList.addAll(unitMap.keySet()); keyList.addAll(bigUnitMap.keySet()); }中文转数字
上面说到,若对应索引处的字符为字典中的值,意味着可以转换为数字。因此需提供一个将中文数字转换为对应阿拉伯数字的方法,下面是对应的代码:
/** * 提取字符串中的数字(若存在非数字的汉字则进行忽略) * * @param str * @return */ private static long chineseToNumber(String str) { // 若字符串为空,则返回默认值-1 if (str == null || str.length() == 0) { return -1L; } /* 进行运算的栈,运算规则是: 1、若获取到的字符为非字典值,则意味着该字符串不是数字,就抛出异常 2、若为从零到九的基础数字,则直接压入栈中; 3、若为十,百,千这种普通的计数单位,则需判断栈是否为空,不为空时将栈中的数字取出与该计数单位相乘后再次压入栈中。 为空则直接将对应的计数单位压入栈中。 4、若为万,亿这种大的计数单位,则将栈中的元素进行累加后获得栈累加值,接着判断当前的大计数位是否比之前的大, 若大,则需将栈累加值与之前的全局累加值想加后再进行相乘,将计算的值赋给全局累加值。若不大,则将栈累加值与大计数单位相乘 后再与全局累加值进行相加。 5、当退出循环后,需检查操作数栈是否为空,若不为空,则将栈中的值依次取出累加到全局累计值上。、 6、将最后的全局累加值进行返回就可得到转换后的数字 */ LinkedList<Long> operateNumStack = new LinkedList<>(); long maxBigUnit = 0L; long num = 0L, currentSum; for (int i = 0; i < str.length(); i++) { char currCh = str.charAt(i); if (!keyList.contains(currCh)) { throw new RuntimeException("该字符串不能转换为数字"); } if (basicNumMap.containsKey(currCh)) { operateNumStack.push(basicNumMap.get(currCh)); } else if (unitMap.containsKey(currCh)) { if (operateNumStack.isEmpty()) { operateNumStack.push(unitMap.get(currCh)); } else { operateNumStack.push(operateNumStack.pop() * unitMap.get(currCh)); } }else if (bigUnitMap.containsKey(currCh)) { currentSum = 0L; while (!operateNumStack.isEmpty()) { currentSum += operateNumStack.pop(); } Long currentBigUnit = bigUnitMap.get(currCh); if (currentBigUnit <= maxBigUnit) { num += currentSum * bigUnitMap.get(currCh); } else { num = (num + currentSum) * bigUnitMap.get(currCh); maxBigUnit = currentBigUnit; } } } while (!operateNumStack.isEmpty()) { num += operateNumStack.pop(); } return num; }中文字符串比较器
对于Java来说,排序时如果不是数字或字母,则需要通过自定义比较器来实现排序。下面是获取自定义排序器的代码:
/** * 获取中文比较的比较器 * * @return */ public static Comparator<String> chineseComp() { return new Comparator<String>() { @Override public int compare(String str1, String str2) { int i1 = 0, i2 = 0; StringBuilder sb1 = new StringBuilder(); StringBuilder sb2 = new StringBuilder(); Collator collator = Collator.getInstance(Locale.CHINESE); while (i1 < str1.length() && i2 < str2.length()) { char ch1 = str1.charAt(i1); char ch2 = str2.charAt(i2); if (ch1 == ch2) { i1++; i2++; continue; } if (Character.isDigit(ch1) && Character.isDigit(ch2)) { // 收集字符串1中的数字 while (Character.isDigit(str1.charAt(i1)) && i1 < str1.length()) { sb1.append(str1.charAt(i1++)); } // 收集字符串2中的数字 while (Character.isDigit(str2.charAt(i2)) && i2 < str2.length()) { sb2.append(str2.charAt(i2++)); } long l1 = Long.parseLong(sb1.toString()); long l2 = Long.parseLong(sb2.toString()); if (l1 - l2 != 0) { return Long.compare(l1, l2); } sb1.setLength(0); sb2.setLength(0); } else if (String.valueOf(ch1).matches("[a-zA-Z]") && String.valueOf(ch2).matches("[a-zA-Z]")) { return Character.compare(Character.toLowerCase(ch1), Character.toLowerCase(ch2)); } else if (keyList.contains(ch1) && keyList.contains(ch2)) { // 收集字符串1中的数字 while (keyList.contains(str1.charAt(i1)) && i1 < str1.length()) { sb1.append(str1.charAt(i1++)); } // 收集字符串2中的数字 while (keyList.contains(str2.charAt(i2)) && i2 < str2.length()) { sb2.append(str2.charAt(i2++)); } long l1 = chineseToNumber(sb1.toString()); long l2 = chineseToNumber(sb2.toString()); if (l1 - l2 != 0) { return Long.compare(l1, l2); } sb1.setLength(0); sb2.setLength(0); } else { return collator.compare(Character.toString(ch1), Character.toString(ch2)); } } return 1; } }; }
到此关键的代码就已经介绍完毕,下面给出所有的代码:
import java.text.Collator;import java.util.Arrays;import java.util.Comparator;import java.util.HashMap;import java.util.HashSet;import java.util.LinkedList;import java.util.Locale;import java.util.Map;import java.util.Set;public class ChineseCompUtils { public static void main(String[] args) { String[] strArr = { "龙跃苑一区三号楼二单元101号", "龙跃苑二区四号楼五单元201号", "龙跃苑一区八号楼六单元101号", "龙跃苑四区十二号楼五单元301号", "龙跃苑二区十七号楼二单元501号", "龙跃苑三区八号楼三单元401号", "龙跃苑一区三号楼二单元201号", "龙跃苑一区九号楼二单元601号", "龙跃苑一区二十二号楼二单元402号", "龙跃苑三区一号楼五单元301号", "龙跃苑三区四号楼一单元501号", "龙跃苑三区十一号楼六单元301号", "龙跃苑二区三号楼二单元201号", "龙跃苑四区八号楼一单元301号", "龙跃苑二区二号楼四单元301号", "龙跃苑四区三号楼九单元401号", "龙跃苑二区五号楼二单元201号", "龙跃苑四区二十八号楼二单元501号", "龙跃苑二区三号楼一单元301号", "龙跃苑一区六号楼二单元401号", "龙跃苑一区十七号楼二单元301号", "龙跃苑一区三号楼十七单元301号", "龙跃苑三区十一号楼二单元602号", "龙跃苑三区三号楼二单元201号", }; Arrays.sort(strArr, chineseComp()); for (int i = 0; i < strArr.length; i++) { System.out.println(strArr[i]); } } private static Set<Character> keyList = new HashSet<>(); private static Map<Character, Long> basicNumMap = new HashMap<>(); private static Map<Character, Long> unitMap = new HashMap<>(); private static Map<Character, Long> bigUnitMap = new HashMap<>(); static { // 初始化basicNumMap basicNumMap.put('零', 0L); basicNumMap.put('一', 1L); basicNumMap.put('二', 2L); basicNumMap.put('三', 3L); basicNumMap.put('四', 4L); basicNumMap.put('五', 5L); basicNumMap.put('六', 6L); basicNumMap.put('七', 7L); basicNumMap.put('八', 8L); basicNumMap.put('九', 9L); // 初始化unitMap unitMap.put('十', 10L); unitMap.put('百', 100L); unitMap.put('千', 1000L); // 初始化unitMap bigUnitMap.put('万', 10000L); bigUnitMap.put('亿', 1_0000_0000L); // 初始化keyList keyList.addAll(basicNumMap.keySet()); keyList.addAll(unitMap.keySet()); keyList.addAll(bigUnitMap.keySet()); } /** * 获取中文比较的比较器 * * @return */ public static Comparator<String> chineseComp() { return new Comparator<String>() { @Override public int compare(String str1, String str2) { int i1 = 0, i2 = 0; StringBuilder sb1 = new StringBuilder(); StringBuilder sb2 = new StringBuilder(); Collator collator = Collator.getInstance(Locale.CHINESE); while (i1 < str1.length() && i2 < str2.length()) { char ch1 = str1.charAt(i1); char ch2 = str2.charAt(i2); if (ch1 == ch2) { i1++; i2++; continue; } if (Character.isDigit(ch1) && Character.isDigit(ch2)) { // 收集字符串1中的数字 while (Character.isDigit(str1.charAt(i1)) && i1 < str1.length()) { sb1.append(str1.charAt(i1++)); } // 收集字符串2中的数字 while (Character.isDigit(str2.charAt(i2)) && i2 < str2.length()) { sb2.append(str2.charAt(i2++)); } long l1 = Long.parseLong(sb1.toString()); long l2 = Long.parseLong(sb2.toString()); if (l1 - l2 != 0) { return Long.compare(l1, l2); } sb1.setLength(0); sb2.setLength(0); } else if (String.valueOf(ch1).matches("[a-zA-Z]") && String.valueOf(ch2).matches("[a-zA-Z]")) { return Character.compare(Character.toLowerCase(ch1), Character.toLowerCase(ch2)); } else if (keyList.contains(ch1) && keyList.contains(ch2)) { // 收集字符串1中的数字 while (keyList.contains(str1.charAt(i1)) && i1 < str1.length()) { sb1.append(str1.charAt(i1++)); } // 收集字符串2中的数字 while (keyList.contains(str2.charAt(i2)) && i2 < str2.length()) { sb2.append(str2.charAt(i2++)); } long l1 = chineseToNumber(sb1.toString()); long l2 = chineseToNumber(sb2.toString()); if (l1 - l2 != 0) { return Long.compare(l1, l2); } sb1.setLength(0); sb2.setLength(0); } else { return collator.compare(Character.toString(ch1), Character.toString(ch2)); } } return 1; } }; } /** * 提取字符串中的数字(若存在非数字的汉字则进行忽略) * * @param str * @return */ private static long chineseToNumber(String str) { // 若字符串为空,则返回默认值-1 if (str == null || str.length() == 0) { return -1L; } /* 进行运算的栈,运算规则是: 1、若获取到的字符未非字典值,意味着该字符串不是数字,就抛出异常 2、若为从零到九的基础数字,则直接压入栈中; 3、若为十,百,千这种普通的计数单位,则需判断栈是否为空,不为空时将栈中的数字取出与该计数单位相乘后再次压入栈中。 为空则直接将对应的计数单位压入栈中。 4、若为万,亿这种大的计数单位,则将栈中的元素进行累加后获得栈累加值,接着判断当前的大计数位是否比之前的大, 若大,则需将栈累加值与之前的全局累加值想加后再进行相乘,将计算的值赋给全局累加值。若不大,则将栈累加值与大计数单位相乘 后再与全局累加值进行相加。 5、当退出循环后,需检查操作数栈是否为空,若不为空,则将栈中的值依次取出累加到全局累计值上。、 6、将最后的全局累加值进行返回就可得到转换后的数字 */ LinkedList<Long> operateNumStack = new LinkedList<>(); // 操作数栈 long maxBigUnit = 0L; long num = 0L, currentSum; for (int i = 0; i < str.length(); i++) { char currCh = str.charAt(i); if (!keyList.contains(currCh)) { throw new RuntimeException("该字符串不能转换为数字"); } if (basicNumMap.containsKey(currCh)) { operateNumStack.push(basicNumMap.get(currCh)); } else if (unitMap.containsKey(currCh)) { if (operateNumStack.isEmpty()) { operateNumStack.push(unitMap.get(currCh)); } else { operateNumStack.push(operateNumStack.pop() * unitMap.get(currCh)); } } else if (bigUnitMap.containsKey(currCh)) { currentSum = 0L; while (!operateNumStack.isEmpty()) { currentSum += operateNumStack.pop(); } Long currentBigUnit = bigUnitMap.get(currCh); if (currentBigUnit <= maxBigUnit) { num += currentSum * bigUnitMap.get(currCh); } else { num = (num + currentSum) * bigUnitMap.get(currCh); maxBigUnit = currentBigUnit; } } } while (!operateNumStack.isEmpty()) { num += operateNumStack.pop(); } return num; }}
执行结果如下所示:
标签: #java字符数字排序 #java对中文排序