我有一个比较器,它对包含字母和数字的字符串数组进行排序,但似乎无法识别以我正在寻找的方式对它们进行排序的正则表达式。
我使用this question作为比较器的参考。
array={string-a01,string-a20,string-a100,string-b01,string-b20,string-b100,string-c01,string-c20,string-c100 etc.}
Collections.sort(array, new Comparator<String>(){
public int compare(String o1, String o2) {
return extractInt(o1) - extractInt(o2);
}
int extractInt(String s) {
String num = s.replaceAll("\\D", "");
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
});
for (String element : array) {
System.out.println(element);
}
在介绍比较器之前,输出是:
string-a01, string-a100, string-a20, string-b01, string-b100, string-b20, string-c01, string-c20, string-c100
此代码产生的输出是:
string-a01, string-b01, string-c01 string-a20, string-b20, string-c20 string-a100, string-b100, string-c100
我希望它产生的输出是:
string-a01, string-a20, string-a100, string-b01, string-b20, string-b100, string-c01, string-c20, string-c100
编辑:编辑澄清。在添加比较器之前,阵列已更改并输出。
答案 0 :(得分:3)
假设string
部分实际上不仅仅是"string"
。您可以提取结尾的字母部分和数字部分,并使用复合比较器进行比较:
String[] array = { "string-a20", "string-a01", "string-b01",
"string-b20", "string-c01", "string-c20",
"string-a100", "string-b100", "string-c100" };
Pattern p = Pattern.compile("^.*?-([A-Za-z]+)(\\d+)$");
List<String> result = Arrays.stream(array)
.map(p::matcher)
.filter(Matcher::find)
.sorted(Comparator.comparing((Matcher m) -> m.group(1)) // Compare the letter part
.thenComparingInt(m -> Integer.parseInt(m.group(2)))) // Compare the number part
.map(m -> m.group(0)) // Map back to String
.collect(Collectors.toList());
System.out.println(result);
输出:
[string-a01, string-a20, string-a100, string-b01, string-b20, string-b100, string-c01, string-c20, string-c100]
旧版本(不得不重新创建Matcher
s):
Arrays.sort(array, new Comparator<String>() {
Pattern p = Pattern.compile("^.*?-([A-Za-z]+)(\\d+)$");
@Override
public int compare(String o1, String o2) {
Matcher m1 = p.matcher(o1);
Matcher m2 = p.matcher(o2);
if(!(m1.find() && m2.find()))
return 0; // Or throw a format exception
int comparison = m1.group(1).compareTo(m2.group(1));
return comparison != 0
? comparison
: Integer.compare(Integer.parseInt(m1.group(2)), Integer.parseInt(m2.group(2)));
}
});
答案 1 :(得分:1)
您正在删除extractInt
方法中的字母字符,因此您无法在比较中使用它们。
您应该使用否 Comparator
对其进行排序,这将使用默认的词典排序算法(java.lang.String
实现Comparable<String>
)对它们进行排序。
示例强>
// test array
String[] s = {"string-a01","string-a01","string-b01","string-b02","string-c02","string-c02"};
// sorting with null Comparator, will sort if the type implements Comparable -
// which String does
Arrays.sort(s);
// printing in human-readable form
System.out.println(
Arrays.toString(s)
);
<强>输出强>
[string-a01, string-a01, string-b01, string-b02, string-c02, string-c02]
备注强>
如果您想删除重复项(可能是您对问题的意图 - 不清楚),请将数组元素添加到TreeSet
:
Set<String> deduplicated = new TreeSet<>(Arrays.asList(s));
如果您的排序算法必须采取行动以使2
出现在12
之前,那么您需要从元素中提取整数值而不将其删除,并且只有当String
s的其余部分相等时才进行比较。
答案 2 :(得分:1)
听起来你想要在&#34;领先的字符串&#34;上排序字符串,即一切都到数字;如果前导字符串相等,则比较后续数字。
将字符串拆分为&#34;字符串&#34;和&#34;整数&#34;你可以先输入&#34;第一个尾随数字&#34;,即字符串中第一个字符的位置,它与字符串末尾之间没有非数字:
int firstTrailingDigit(String s) {
int i = s.length();
while (i > 0 && Character.isDigit(s.charAt(i - 1))) {
--i;
}
return i;
}
然后您可以在比较器中使用它:
public int compare(String a, String b) {
int ftdA = firstTrailingDigit(a);
int ftdB = firstTrailingDigit(b);
// Get the leading strings, and compare.
String sA = a.substring(0, ftdA);
String sB = b.substring(0, ftdB);
int compareStrings = sA.compareTo(sB);
if (compareStrings != 0) {
// If they're not equal, return the result of the comparison.
return compareStrings;
}
// Get the trailing numbers from the strings, and compare.
int iA = Integer.parseInt(a.substring(ftdA));
int iB = Integer.parseInt(b.substring(ftdB));
return Integer.compare(iA, iB);
}
输入:
String[] array = {"string-a01","string-a20","string-a100","string-b01","string-b20","string-b100","string-c01","string-c20","string-c100"};
输出:
[string-a01, string-a20, string-a100, string-b01, string-b20, string-b100, string-c01, string-c20, string-c100]