【问题标题】:How to compare versions in Ruby?如何比较 Ruby 中的版本?
【发布时间】:2010-01-12 18:10:47
【问题描述】:

如何编写一段代码来比较一些版本的字符串并获取最新的?

例如像这样的字符串:'0.1', '0.2.1', '0.44'

【问题讨论】:

  • 我需要比较悲观的版本约束,但我不想依赖 RubyGems 来做这件事,所以我写了一个简单的 Version 类来满足我的一切需求:@987654321 @

标签: ruby


【解决方案1】:
Gem::Version.new('0.4.1') > Gem::Version.new('0.10.1')

【讨论】:

  • Gem::Version... 语法让我觉得我需要安装一个 gem。但这不是必需的。
  • 注意:这在 Ruby 1.x 上为我提供了关于未定义变量“Gem”的错误,但在 Ruby 2.x 上可以正常工作。就我而言,我正在检查 RUBY_VERSION 是否是 Ruby 1.x(不是 2.x),所以我只是像 John Hyland 和 DigitalRoss 那样做了 RUBY_VERSION.split('.')[0] == "1" 。跨度>
  • Gem::Dependency.new(nil, '~> 1.4.5').match?(nil, '1.4.6beta4')
  • @uliwitness 这不是 Ruby 1.x 与 2.x;这是 1.8.x 与 1.9+。 Ruby 到 1.8.x 默认不包含 ruby​​gems;您需要 require 'rubygems' 才能访问 Gem 命名空间。但是,从 1.9 开始,它会自动包含在内。
  • 这也适用于比较通配符 NPM 版本。 +1
【解决方案2】:

如果需要查看pessimistic version constraints,可以这样使用Gem::Dependency

Gem::Dependency.new('', '~> 1.4.5').match?('', '1.4.6beta4')

【讨论】:

  • 较新的版本似乎需要一个字符串作为名称。空字符串可以正常工作,即Gem::Dependency.new('', '~> 1.4.5').match?('', '1.4.6beta4')
【解决方案3】:
class Version < Array
  def initialize s
    super(s.split('.').map { |e| e.to_i })
  end
  def < x
    (self <=> x) < 0
  end
  def > x
    (self <=> x) > 0
  end
  def == x
    (self <=> x) == 0
  end
end
p [Version.new('1.2') < Version.new('1.2.1')]
p [Version.new('1.2') < Version.new('1.10.1')]

【讨论】:

  • 与此处的其他一些答案一样,您似乎在进行字符串比较而不是数字比较,这在比较“0.10”和“0.4”等版本时会出现问题。
  • 赞成简洁的解决方案,不需要安装 gem。
  • 对于它的价值:vers = (1..3000000).map{|x| "0.0.#{x}"}; 'ok' puts Time.now; vers.map{|v| ComparableVersion.new(v) }.sort.first; puts Time.now # 24 seconds 2013-10-29 13:36:09 -0700 2013-10-29 13:36:33 -0700 =&gt; nil puts Time.now; vers.map{|v| Gem::Version.new(v) }.sort.first; puts Time.now # 41 seconds 2013-10-29 13:36:53 -0700 2013-10-29 13:37:34 -0700 代码 blob 让它变得丑陋,但基本上,使用 this vs Gem::Version 大约快两倍。
  • 一个版本不是一个数组。
【解决方案4】:

您可以使用Versionomy gem(可在github 获取):

require 'versionomy'

v1 = Versionomy.parse('0.1')
v2 = Versionomy.parse('0.2.1')
v3 = Versionomy.parse('0.44')

v1 < v2  # => true
v2 < v3  # => true

v1 > v2  # => false
v2 > v3  # => false

【讨论】:

  • 我已经看到了,但是需要我使用 2 个宝石来做一件非常简单的事情。我想把它作为最后的选择。
  • “不要重新发明轮子”。因为它很简单并不意味着程序员没有投入工作和思考。使用 gem、阅读代码并从中学习——然后继续做更​​大更好的事情!
  • 依赖管理和版本维护是一个难题,可能比比较两个版本的任务困难得多。我完全同意在这种情况下引入另外两个依赖项应该是最后的手段。
【解决方案5】:

我愿意

a1 = v1.split('.').map{|s|s.to_i}
a2 = v2.split('.').map{|s|s.to_i}

那你就可以了

a1 <=> a2

(可能还有所有其他“通常”的比较)。

...如果你想要 &lt;&gt; 测试,你可以做例如

(a1 <=> a2) < 0

如果你愿意,也可以做更多的函数包装。

【讨论】:

  • Array.class_eval {include Comparable} 将使所有数组响应 等。或者,如果您只想对某些数组执行此操作:a = [1, 2]; a.扩展(可比)
  • 我发现这个解决方案的问题是它返回“1.2.0”大于“1.2”
【解决方案6】:

Gem::Version 是去这里的简单方法:

%w<0.1 0.2.1 0.44>.map {|v| Gem::Version.new v}.max.to_s
=> "0.44"

【讨论】:

  • 比需要 c 扩展的 versionomy 好得多!?
  • 我认为 'max' 行不通。它会报告 0.5 大于 0.44。比较 semver 版本时,这是不正确的。
  • 这似乎已在最新的 Gem::Version 中得到修复。 0.44 现在正确报告为高于 0.5。
【解决方案7】:

如果您想在不使用任何宝石的情况下手动完成,则应该可以使用类似以下的方法,尽管它看起来有点过时。

versions = [ '0.10', '0.2.1', '0.4' ]
versions.map{ |v| (v.split '.').collect(&:to_i) }.max.join '.'

本质上,您将每个版本字符串转换为整数数组,然后使用array comparison operator。如果这是在有人需要维护的代码中进行,您可以分解组件步骤以使某些东西更容易遵循。

【讨论】:

    【解决方案8】:

    我有同样的问题,我想要一个无宝石版本的比较器,想出了这个:

    def compare_versions(versionString1,versionString2)
        v1 = versionString1.split('.').collect(&:to_i)
        v2 = versionString2.split('.').collect(&:to_i)
        #pad with zeroes so they're the same length
        while v1.length < v2.length
            v1.push(0)
        end
        while v2.length < v1.length
            v2.push(0)
        end
        for pair in v1.zip(v2)
            diff = pair[0] - pair[1]
            return diff if diff != 0
        end
        return 0
    end
    

    【讨论】:

      猜你喜欢
      • 2017-10-26
      • 2011-10-18
      • 2011-03-01
      • 2023-04-05
      • 2012-11-08
      • 2023-03-20
      • 2016-07-23
      • 1970-01-01
      相关资源
      最近更新 更多