【发布时间】:2014-06-05 23:13:30
【问题描述】:
我正在尝试在另一个问题上使用 Sander Pham 建议的代码。我需要像 Windows 资源管理器那样对字符串名称的 java ArrayList 进行排序。他的代码适用于所有问题,但只有一个问题。我本来想对这个问题发表评论,但我需要更多的声誉点来发表评论。无论如何......他建议使用自定义比较器实现类并使用它来比较字符串名称。这是该类的代码:
class IntuitiveStringComparator implements Comparator<String>
{
private String str1, str2;
private int pos1, pos2, len1, len2;
public int compare(String s1, String s2)
{
str1 = s1;
str2 = s2;
len1 = str1.length();
len2 = str2.length();
pos1 = pos2 = 0;
int result = 0;
while (result == 0 && pos1 < len1 && pos2 < len2)
{
char ch1 = str1.charAt(pos1);
char ch2 = str2.charAt(pos2);
if (Character.isDigit(ch1))
{
result = Character.isDigit(ch2) ? compareNumbers() : -1;
}
else if (Character.isLetter(ch1))
{
result = Character.isLetter(ch2) ? compareOther(true) : 1;
}
else
{
result = Character.isDigit(ch2) ? 1
: Character.isLetter(ch2) ? -1
: compareOther(false);
}
pos1++;
pos2++;
}
return result == 0 ? len1 - len2 : result;
}
private int compareNumbers()
{
// Find out where the digit sequence ends, save its length for
// later use, then skip past any leading zeroes.
int end1 = pos1 + 1;
while (end1 < len1 && Character.isDigit(str1.charAt(end1)))
{
end1++;
}
int fullLen1 = end1 - pos1;
while (pos1 < end1 && str1.charAt(pos1) == '0')
{
pos1++;
}
// Do the same for the second digit sequence.
int end2 = pos2 + 1;
while (end2 < len2 && Character.isDigit(str2.charAt(end2)))
{
end2++;
}
int fullLen2 = end2 - pos2;
while (pos2 < end2 && str2.charAt(pos2) == '0')
{
pos2++;
}
// If the remaining subsequences have different lengths,
// they can't be numerically equal.
int delta = (end1 - pos1) - (end2 - pos2);
if (delta != 0)
{
return delta;
}
// We're looking at two equal-length digit runs; a sequential
// character comparison will yield correct results.
while (pos1 < end1 && pos2 < end2)
{
delta = str1.charAt(pos1++) - str2.charAt(pos2++);
if (delta != 0)
{
return delta;
}
}
pos1--;
pos2--;
// They're numerically equal, but they may have different
// numbers of leading zeroes. A final length check will tell.
return fullLen2 - fullLen1;
}
private int compareOther(boolean isLetters)
{
char ch1 = str1.charAt(pos1);
char ch2 = str2.charAt(pos2);
if (ch1 == ch2)
{
return 0;
}
if (isLetters)
{
ch1 = Character.toUpperCase(ch1);
ch2 = Character.toUpperCase(ch2);
if (ch1 != ch2)
{
ch1 = Character.toLowerCase(ch1);
ch2 = Character.toLowerCase(ch2);
}
}
return ch1 - ch2;
}
}
在使用它时,它工作得很好,除非字符串名称后面没有数字。如果它没有数字,则将其放在列表的末尾,这是错误的。如果它没有数字,它应该在开头。
即
filename.jpg
filename2.jpg
filename03.jpg
filename3.jpg
目前它的排序...
filename2.jpg
filename03.jpg
filename3.jpg
filename.jpg
我需要在代码中进行哪些更改才能更正此行为?
谢谢
【问题讨论】:
-
这种排序是否有可用的规则集?如果有 file5b7.jpg 之类的名称怎么办,那么其他扩展名呢?扩展点之前的最后一个数字总是特殊处理吗?将文件名分成三部分名称,数字,分机并让比较器比较名字和相等的数字然后分机会更简单吗?该数字将转换为 int。
-
对。扩展点之前的文件名和编号是被排序的点。几乎只需要准确模仿 Windows 资源管理器的排序方式。更多示例是... filename00.jpg filename0.jpg filename0b.jpg filename0b1.jpg filename0b02.jpg filename0c.jpg filename1.jpg 我相信,在当前给出的代码中,这就是行为。我注意到唯一不起作用的是,如果文件名后面根本没有数字,它会排在其他所有内容之后,而不是之前。
-
不会有其他扩展。所以不同的扩展并不是一个真正的问题。
标签: java windows sorting comparator explorer