添加到答案所作@stanislav。使用提供的答案时,我遇到了一些问题:
- 大写字母和小写字母由其ASCII码之间的字符分隔。当要排序的字符串包含_或其他字符(在ASCII中的小写字母和大写字母之间)时,这会中断流程。
- 如果两个字符串相同,除了前导零计数不同,该函数将返回0,这将使排序取决于字符串在列表中的原始位置。
这两个问题已在新代码中修复。我做了一些函数,而不是一些重复的代码集。differentCaseCompared变量用于跟踪两个字符串是否相同(除了大小写不同)。如果是这样,则返回减去的前不同大小写字符的值。这样做是为了避免两个字符串因大小写不同而返回0的问题。
public class NaturalSortingComparator implements Comparator<String> {
@Override
public int compare(String string1, String string2) {
int lengthOfString1 = string1.length();
int lengthOfString2 = string2.length();
int iteratorOfString1 = 0;
int iteratorOfString2 = 0;
int differentCaseCompared = 0;
while (true) {
if (iteratorOfString1 == lengthOfString1) {
if (iteratorOfString2 == lengthOfString2) {
if (lengthOfString1 == lengthOfString2) {
return differentCaseCompared;
}
else {
return lengthOfString1 - lengthOfString2;
}
}
else
return -1;
}
if (iteratorOfString2 == lengthOfString2) {
return 1;
}
char ch1 = string1.charAt(iteratorOfString1);
char ch2 = string2.charAt(iteratorOfString2);
if (Character.isDigit(ch1) && Character.isDigit(ch2)) {
iteratorOfString1 = skipLeadingZeroes(string1, lengthOfString1, iteratorOfString1);
iteratorOfString2 = skipLeadingZeroes(string2, lengthOfString2, iteratorOfString2);
int endPositionOfNumbersInString1 = findEndPositionOfNumber(string1, lengthOfString1, iteratorOfString1);
int endPositionOfNumbersInString2 = findEndPositionOfNumber(string2, lengthOfString2, iteratorOfString2);
int lengthOfDigitsInString1 = endPositionOfNumbersInString1 - iteratorOfString1;
int lengthOfDigitsInString2 = endPositionOfNumbersInString2 - iteratorOfString2;
if (lengthOfDigitsInString1 != lengthOfDigitsInString2)
return lengthOfDigitsInString1 - lengthOfDigitsInString2;
while (iteratorOfString1 < endPositionOfNumbersInString1) {
if (string1.charAt(iteratorOfString1) != string2.charAt(iteratorOfString2))
return string1.charAt(iteratorOfString1) - string2.charAt(iteratorOfString2);
iteratorOfString1++;
iteratorOfString2++;
}
} else {
if (ch1 != ch2) {
if (!ignoreCharacterCaseEquals(ch1, ch2))
return Character.toLowerCase(ch1) - Character.toLowerCase(ch2);
if (differentCaseCompared == 0) {
differentCaseCompared = ch1 - ch2;
}
}
iteratorOfString1++;
iteratorOfString2++;
}
}
}
private boolean ignoreCharacterCaseEquals(char character1, char character2) {
return Character.toLowerCase(character1) == Character.toLowerCase(character2);
}
private int findEndPositionOfNumber(String string, int lengthOfString, int end) {
while (end < lengthOfString && Character.isDigit(string.charAt(end)))
end++;
return end;
}
private int skipLeadingZeroes(String string, int lengthOfString, int iteratorOfString) {
while (iteratorOfString < lengthOfString && string.charAt(iteratorOfString) == '0')
iteratorOfString++;
return iteratorOfString;
}
}
以下是我使用的单元测试。
public class NaturalSortingComparatorTest {
private int NUMBER_OF_TEST_CASES = 100000;
@Test
public void compare() {
NaturalSortingComparator naturalSortingComparator = new NaturalSortingComparator();
List<String> expectedStringList = getCorrectStringList();
List<String> testListOfStrings = createTestListOfStrings();
runTestCases(expectedStringList, testListOfStrings, NUMBER_OF_TEST_CASES, naturalSortingComparator);
}
private void runTestCases(List<String> expectedStringList, List<String> testListOfStrings,
int numberOfTestCases, Comparator<String> comparator) {
for (int testCase = 0; testCase < numberOfTestCases; testCase++) {
Collections.shuffle(testListOfStrings);
testListOfStrings.sort(comparator);
Assert.assertEquals(expectedStringList, testListOfStrings);
}
}
private List<String> getCorrectStringList() {
return Arrays.asList(
"1", "01", "001", "2", "02", "10", "10", "010",
"20", "100", "_1", "_01", "_2", "_200", "A 02",
"A01", "a2", "A20", "t1A", "t1a", "t1AB", "t1Ab",
"t1aB", "t1ab", "T010T01", "T0010T01");
}
private List<String> createTestListOfStrings() {
return Arrays.asList(
"10", "20", "A20", "2", "t1ab", "01", "T010T01", "t1aB",
"_2", "001", "_200", "1", "A 02", "t1Ab", "a2", "_1", "t1A", "_01",
"100", "02", "T0010T01", "t1AB", "10", "A01", "010", "t1a");
}
}
建议欢迎!我不确定添加功能是否会改变除可读性之外的其他内容。
PS:很抱歉为这个问题添加另一个答案。但是我没有足够的代表来评论我为自己使用而修改的答案。