【问题标题】:String/Range comparison problem字符串/范围比较问题
【发布时间】:2023-03-08 12:55:01
【问题描述】:

这对于类似的事情是有意义的:

irb(main):001:0> ["b", "aa", "d", "dd"].sort
=> ["aa", "b", "d", "dd"]

但不适用于:

irb(main):002:0> ("B".."AA").each{ |x| print "#{x}," }
=> "B".."AA"

应该产生: B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z, AA,=> "B".."AA" 但是 "B" > "AA" => true

不同于 "B".."BA" ("B" > "BA" => false):

irb(main):003:0> ("B".."BA").each{ |x| print "#{x}," }
B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AS,AT,AU,AV,AW,AX,AY,AZ,BA,=> "B".."BA"

有什么建议可以让 "b".."aa" 在 ruby​​ 中按预期工作?

我用

  • irb 0.9.5(05/04/13) 红宝石 1.8.7
  • (2009-06-12 补丁级别 174) [i486-linux]
  • Linux 2.6.31-19-generic #56-Ubuntu SMP Thu Jan 28 01:26:53 UTC 2010 i686 GNU/Linux

【问题讨论】:

  • 我认为您在这里有一个很好的问题,但它的措辞非常混乱。
  • 随意编辑我的问题我不是以英语为母语的人

标签: ruby language-design


【解决方案1】:

最好的方法是继承 String 并重新定义比较运算符以满足您的需求。然后使用您的新类来确定范围。

class MyString < String
  def initialize str=""
    super str
  end

  def <=>(other)
    length_cmp = self.length <=> other.length
    return length_cmp unless length_cmp == 0
    super other
  end
end

现在您可以确保一列出现在另一列之前。

"b" < "aa" #=> false
MyString.new("b") < MyString.new("aa") #=> true

注意:只有任何比较运算符左侧的字符串需要属于 MyString 类:

MyString.new("b") < "aa" #=> true
"aa" > MyString.new("b") #=> false

【讨论】:

    【解决方案2】:

    看起来 Ruby 正在使用 succ,但首先它会检查 end&gt;=start,因为这里是错误的,所以它甚至没有尝试。

    诚然,String#succ 在这里是一只奇怪的野兽:字符串的后继者并不总是大于字符串,使用它自己的比较方法。所以我不确定这在技术上是否是一个错误。不过,如果您不知道这个无证检查,它看起来确实是 pretty confusing

    再一次,从这里的一些其他答案来看,它看起来在某些版本的 Ruby 中确实可以正常工作,所以也许它在 1.9 中已修复?

    【讨论】:

    • 不适用于 ruby​​ 1.9.1p376(2009-12-07 修订版 26041)[i486-linux]
    【解决方案3】:

    确实在String类中,和String#succ并不完全协调


    我想如果每个 a, b 最终由 a.succ.succ... 产生 b 会很好,a b 返回 -1 也是真的。这会很好的一个原因是,实际上正是 &lt;=&gt;succ 首先用于实现范围。因此,正如您所指出的,.succ 最终将完成扩展的 Ruby 字符串范围不起作用,因为 &lt;=&gt; 测试与其相矛盾并终止循环。

    所以是的,至少对于 String 而言,由 &lt;=&gt; 定义的排序与 #succ 方法排序不匹配。这是一些开发人员避免使用succ 的原因之一。

    【讨论】:

    • 没错。我在另一个问题上扩展了这个this comment
    【解决方案4】:

    有什么建议可以让 "b".."aa" 在 ruby​​ 中按预期工作?

    这在 ruby​​ 1.8.7(2009-06-12 补丁级别 174)和 ruby​​ 1.9.1p376(2009-12-07 修订版 26041)[i486-linux] 中不起作用


    "b".."ba" 确实有效...

    irb(main):001:0> ("b".."ba").each {|x|打印“#{x}”} b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba => "b".."ba"

    【讨论】:

    • 引用不是问题,因为这里没有插值。也许这是一个版本问题:在 1.8.7 上,您的示例打印“b”..“aa”(范围本身,没有元素)。您使用的是哪个版本的 Ruby?
    • ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux] :你是对的 - 它在 irb 中不起作用,因为我有一个备用的“所以它没有工作 - 我重新输入,“b”..“aa”和“b”..'aa' 工作
    • ruby 1.8.7 (2008-08-11 patchlevel 72) -- 我一定是错过了!
    • 太棒了!很高兴最终能帮上忙!
    【解决方案5】:

    这被报告为 Ruby here 中的一个错误。结果取决于您运行的 Ruby 版本。版本 1.8.6 和 1.9.1 之间存在差异。

    【讨论】:

    • 不,这不是排序顺序:他正在尝试执行“B”..“AA”,Ruby(对他和我而言)计算结果为 []。你可以用任何你喜欢的方式对 [] 进行排序,但它仍然是 []。 :-) 文档似乎表明使用了succ,并且它是为“B”、“C”、...、“Z”、“AA”定义的,所以它应该像他预期的那样工作。
    • 啊,错过了,谢谢。看起来像是某些 Ruby 版本中的错误。
    • 它实际上已在 ruby​​ 1.8.7 (2009-06-12 patchlevel 174) 中修复
    • 是的,“b”..“ba”有效,但“b”..“ab”无效。它也不适用于 ruby​​ 1.9.1p376(2009-12-07 修订版 26041)[i486-linux]
    • 该错误被标记为已拒绝。我认为他们不想修复它。
    猜你喜欢
    • 1970-01-01
    • 2019-05-04
    • 2017-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多