Java 的“sort -V”替代方案

发布于 2025-01-05 23:00:34 字数 190 浏览 1 评论 0原文

我正在寻找 shell 命令的纯 java 替代方案:sort -V。我正在寻找一个可以简单插入的比较器类。 sort -V 命令只是使用版本系统对文件进行排序(即 3.2.0-113.2.0-1 大 10,不是 0.1 大)。

提前致谢!

I'm looking for a pure-java alternative for the shell command: sort -V. I'm looking for a Comparator class that can simply be plugged in.
The sort -V command simply sorts files with a version system (i.e. 3.2.0-11 is 10 bigger than 3.2.0-1, not .1 bigger).

Thanks in advance!

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

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

发布评论

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

评论(2

勿忘初心 2025-01-12 23:00:34

我曾经写过一个通用的“像人类一样”的比较器。我没有代码可以显示,但想法是像这样分割每个字符串:

fragments = empty string collection
buffer = first character of the string
if character is digit, mode = NUMBER, else mode = TEXT
while there are characters left
   c = next character
   if c is digit and mode is NUMBER, add character to buffer
   else if c is not a digit and mode is TEXT, add character to buffer
   else
     add contents of buffer (as string) to the fragments collection,
     flip mode from TEXT to NUMBER or vice versa
     buffer = c
   end if
end while
add remaining contents of buffer to fragments

所以现在你有了一个子字符串列表,其中包含交替的数字片段和非数字片段。 (例如 something-1.0.26.jar 将变为 { 'something-', '1', '.', '0', '.', '26', '.jar ' })

如果对两个字符串都执行此操作,则可以编写一个比较器来逐一比较这对片段:如果两者都是数字,则进行数值比较,如果两者都是文本,则进行字符串比较,如果一个是数字,另一个是文本,数字优先。

我知道这比您想要的要多得多,但在许多情况下这是一段非常有用的代码。

I wrote a generic "like a human" comparator once. I've got no code to show but the idea was to split each string like this:

fragments = empty string collection
buffer = first character of the string
if character is digit, mode = NUMBER, else mode = TEXT
while there are characters left
   c = next character
   if c is digit and mode is NUMBER, add character to buffer
   else if c is not a digit and mode is TEXT, add character to buffer
   else
     add contents of buffer (as string) to the fragments collection,
     flip mode from TEXT to NUMBER or vice versa
     buffer = c
   end if
end while
add remaining contents of buffer to fragments

So now you've got a list of substrings, containing alternating number fragments and non-number fragments. (E.g. something-1.0.26.jar will become { 'something-', '1', '.', '0', '.', '26', '.jar' })

If you do this to both strings, you can then write a comparator that compares the pairs fragments one by one: if both are numbers, do a numerical comparison, if both are texts, string compare, if one is number, the other is text, number comes first.

I know this is a lot more than what you want but it is quite a useful piece of code to have in many situations.

何必那么矫情 2025-01-12 23:00:34

初学者:

如果您的版本字符串定义明确,那么您可以将其拆分为不同的数字并直接进行比较。

3.2.0-11 变为 4 个整数,3、2、0 和 11,而 3.2.0-1 变为 3、2、0 和 1。

假设您将它们放入数组中,您将比较 src[3] <目标[3],源[2] < dest[2], ... 在你的比较器中,你就完成了。

在您的情况下,可以使用 String.split(".-") 轻松完成此操作,然后对结果数组中的每个条目调用 Integer.getInteger(src[n]) 。

高级:

现在,如果您想要“高级”版本,我可以向您展示一个小技巧。如果你将你的值组合成一个长整型,就像这样:

long l=src[3] << (16 * 3) + src[2] << (16 * 2) + src[1] << (16 * 1) + src[0];

这会将所有单独的字段组合成一个可以比较的长整型。
(它需要一点转换,并且第一个字段不能超过版本 # 32767,所有其他字段都可以超过版本 # 32767)

如果您确定没有一个数字会超过 255,那么您甚至可以移动 8 的倍数而不是 16并将它们打包成一个 int (或者一个 long 类型,可以处理最多 7 个字段的版本号——或者 8 个字段,只要第一个字段不超过 127)

这个技术的优点是是你把它从 4 比较到 1 并且你只携带一个值。

专家:

顺便说一句,“专家”版本是将所有这些包装在一个类中,这样您就不必关心它是如何实现的。具有这样的接口的东西:

class VersionNo implements Comparable {
    public VersionNo(String version, File originalFileObject);
    public int compareTo(VersionNo target);
    public String toString();
    public File getOriginalFileObject();
}

现在您可以随时更改您的实现,并且不会影响程序中的任何其他内容 - 您甚至“不需要”考虑单独的比较器,这些比较器在插入任何内容时应该自动排序自尊的有序数据结构。

Beginner:

If your version string is clearly defined then you can split it up into different numbers and compare them directly.

3.2.0-11 becomes 4 ints, 3, 2, 0 and 11 whereas 3.2.0-1 becomes 3, 2, 0 and 1.

Assuming you made them into arrays you compare src[3] < dest[3], src[2] < dest[2], ... inside your comparator and you are done.

This can be done easily in your case with String.split(".-") then calling Integer.getInteger(src[n]) on each entry in the resulting array.

Advanced:

Now, if you want the "Advanced" version of this I can show you a little trick. If you take your values and combine them into a single long--something like this:

long l=src[3] << (16 * 3) + src[2] << (16 * 2) + src[1] << (16 * 1) + src[0];

This will combine all the individual fields into a single long that can be compared.
(it will need a little casting AND the first field cannot go over version # 32767, all the others can go to 65535)

If you are sure none of the numbers will go over 255 then you could even shift by multiples of 8 instead of 16 and pack them into an int (or a long that can handle a version number with up to 7 fields--or 8 as long as the first one doesn't go over 127)

The nice part of this technique is that you take it from 4 compares down to 1 and you are only carrying around a single value.

Expert:

The "Expert" version, by the way, is to wrap all this inside a class so that you really don't care how it's implemented. Something with an interface like this:

class VersionNo implements Comparable {
    public VersionNo(String version, File originalFileObject);
    public int compareTo(VersionNo target);
    public String toString();
    public File getOriginalFileObject();
}

Now you can change your implementation any time you want and not effect anything else in your program--you don't even "Need" to consider a separate comparator, these should automatically sort themselves when inserted in any self-respecting ordered data structure.

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