Java 中按名称对文件排序与 Windows 资源管理器不同

发布于 2024-09-05 19:09:15 字数 457 浏览 6 评论 0原文

我有一个简单的 Java 程序,它读取文件目录并输出文件列表。 我按名称对文件进行排序:

String [] files = dirlist.list();
files = sort(files);

我的问题是它按名称排序的方式与 Windows 资源管理器不同。

例如,如果我有这些文件:abc1.doc、abc12.doc、abc2.doc。

Java 将如下排序:

abc1.doc
abc12.doc
abc2.doc

当我在 Windows 资源管理器中打开文件夹时,我的文件将如下排序:

abc1.doc
abc2.doc
abc12.doc

如何让 Java 像在 Windows 资源管理器中一样对文件进行排序? 这是 Windows 的伎俩吗?

I have a simple Java program which reads a file directory and outputs a file list.
I sort the files by name:

String [] files = dirlist.list();
files = sort(files);

My problem is that it sorts by name in a different way than Windows Explorer does.

For instance if I have these files: abc1.doc, abc12.doc, abc2.doc.

Java will sort like this:

abc1.doc
abc12.doc
abc2.doc

When I open the folder in Windows Explorer, my files are sorted like this:

abc1.doc
abc2.doc
abc12.doc

How can I make Java sort my files like in Windows Explorer?
Is this a Windows trick?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

许仙没带伞 2024-09-12 19:09:16

Windows 资源管理器使用自己的算法。为了像资源管理器一样对文件进行排序,您应该创建一个自定义比较器来实现这一目的:

    public class WindowsExplorerStringComparator 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()
      {
        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++;
        }

        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++;
        }

        int delta = (end1 - pos1) - (end2 - pos2);
        if (delta != 0)
        {
          return delta;
        }

        while (pos1 < end1 && pos2 < end2)
        {
          delta = str1.charAt(pos1++) - str2.charAt(pos2++);
          if (delta != 0)
          {
            return delta;
          }
        }

        pos1--;
        pos2--; 

        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;
      }
    }

现在,像这样使用它:

  Arrays.sort(files, new WindowsExplorerStringComparator());

Windows Explorer uses its own algorithm. In order to sort your files like Explorer does, you should create a custom Comparator to do the trick:

    public class WindowsExplorerStringComparator 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()
      {
        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++;
        }

        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++;
        }

        int delta = (end1 - pos1) - (end2 - pos2);
        if (delta != 0)
        {
          return delta;
        }

        while (pos1 < end1 && pos2 < end2)
        {
          delta = str1.charAt(pos1++) - str2.charAt(pos2++);
          if (delta != 0)
          {
            return delta;
          }
        }

        pos1--;
        pos2--; 

        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;
      }
    }

Now, use it like this:

  Arrays.sort(files, new WindowsExplorerStringComparator());
与他有关 2024-09-12 19:09:16

看起来是这样。

但是,您可以使用 Arrays.sort() 并提供自定义的Comparator,以便它像 Windows 资源管理器一样排序。

It looks that way.

However, you can use Arrays.sort() and supply a custom Comparator so that it sorts like Windows Explorer does.

执手闯天涯 2024-09-12 19:09:16

按字符串排序,然后按名称长度排序。

Sort by string then by name length.

戈亓 2024-09-12 19:09:16

这是在 Java 中实现它的另一次尝试:

Java - 像 Windows 资源管理器一样对字符串进行排序

简而言之,它将两个字符串拆分为字母-数字部分进行比较,并以特定的方式比较这部分,以实现这种排序。

恕我直言,这样就更具可读性了。

This is another try to implement it in Java:

Java - Sort Strings like Windows Explorer

In short it splits the two Strings to compare in Letter - Digit Parts and compares this parts in a specific way to achieve this kind of sorting.

With this its IMHO a bit more readable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文