在Ruby中进行版本排序(包括alpha、beta等)。

22

如何在Ruby中对版本号列表进行排序?我看到了一些关于自然排序的内容,但这已经超出了那个范畴。

输入是一堆像这样的字符串:

input = ['10.0.0b12', '10.0.0b3', '10.0.0a2', '9.0.10', '9.0.3']

我几乎可以用 naturally 宝石完成它:

require 'naturally'
Naturally.sort(input)
=> ["9.0.3", "9.0.10", "10.0.0a2", "10.0.0b12", "10.0.0b3"]    

问题:10.0.0b3在10.0.0b12之后排序,但它应该排在前面。

有人知道有效的解决方法吗?其他语言也可以。


1
这些版本字符串非常不典型。你不太可能找到现成的解决方案,你应该自己编写。 - user229044
我将其更改为使用语义化版本控制。这更加典型。 - Chaim Leib Halbert
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Ajedi32
True。带连字符时,自然排序效果很好,但这种几乎语义版本化的系统仍然很常见。 - Chaim Leib Halbert
3个回答

39

Ruby自带Gem类,它知道版本信息:

ar = ['10.0.0b12', '10.0.0b3', '10.0.0a2', '9.0.10', '9.0.3']

p ar.sort_by { |v| Gem::Version.new(v) }
# => ["9.0.3", "9.0.10", "10.0.0a2", "10.0.0b3", "10.0.0b12"]

2
不错。就它而言——看起来这只按字母顺序处理“alpha”和“beta”。也就是说,['9.0.10rc2', '9.0.10', '9.0.10rc1', '9.0.10a', '9.0.10test'] 会得到 ["9.0.10a", "9.0.10rc1", "9.0.10rc2", "9.0.10test", "9.0.10"]。这应该足够了,因为“alpha/beta/pre-release/rc/release”本来就按字母顺序排列,但如果您的数据偏离太远,可能会有些古怪。 - DreadPirateShawn
1
挺有趣的,它是怎么工作的:https://github.com/rubygems/rubygems/blob/1aa8033952d4eda5ca131039822f9548166ab507/lib/rubygems/version.rb#L336-L361 - Anthony

5
如果你把它解释为“按照每个数字段排序”,那么下面的代码将处理你上面提供的示例输入:
input.map{ |ver| ver.split(%r{[^\d]+}).map(&:to_i) }.zip(input).sort.map(&:last)
=> ["9_0", "9_1", "10_0b3", "10_0b12"]

那就是,
对于每个值,例如10_0b3, 根据非数字字符的长度进行分割,例如["10","0","3"], 将每个数字片段转换为整数,例如[10,0,3], 与原始输入进行合并,得到[[[10, 0, 12], "10_0b12"], [[10, 0, 3], "10_0b3"], [[9, 0], "9_0"], [[9, 1], "9_1"]], 通过[10,0,3] < [10,0,12]进行排序, 获取每个元素的最后一个值,即对应于每个处理过的可排序值的原始输入值。
当然,这仍然是相当定制化的——简单的版本号如"9_0a"和"9_0b"将无法处理,它们都会被视为[9,0]——因此您可能需要进一步调整,但希望这能让您找到一条可行的路径。

编辑:上面的示例输入已更改,因此我更改了正则表达式以确保数字匹配是贪婪的,并且这样仍然有效:

irb(main):018:0> input = ['10.0.0b12', '10.0.0b3', '9.0.10', '9.0.3']
=> ["10.0.0b12", "10.0.0b3", "9.0.10", "9.0.3"]
irb(main):025:0> input.map{ |ver| ver.split(%r{[^\d]+}).map(&:to_i) }.zip(input).sort.map(&:last)
=> ["9.0.3", "9.0.10", "10.0.0b3", "10.0.0b12"]

这确实有所帮助,但beta不是唯一可能的后缀。我们还可以有像“10.0.0a2”这样的alpha版本或者像“10.0.0rc1”这样的发行候选版本。如果这些版本与其他版本并排存在,则排序将中断。 - Chaim Leib Halbert

1

如果您正在使用NuGet并想从Ruby代码中解析、比较或按NuGet的特殊版本控制方案进行排序,则现在有以下方法:

https://rubygems.org/gems/nuget_versions

我特意创建它来解决这个问题。NuGet的版本号有点奇怪,它们是SemVer的超集,还允许使用4个组件而不是3个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接