字符串/范围比较问题

发布于 2024-08-21 04:14:43 字数 893 浏览 6 评论 0原文

这对于诸如 : 之类的事情有意义,

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) ruby​​ 1.8.7
  • (2009-06-12 patchlevel 174) [i486-linux]
  • Linux 2.6.31-19-generic #56-Ubuntu SMP Thu Jan 28 01:26 :53 UTC 2010 i686 GNU/Linux

This make sense for things like :

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

But doesn't for :

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

should produce :
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" but "B" > "AA" => true

Unlike "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"

Any advice to make "b".."aa" work as expected in ruby ?

I use

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

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

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

发布评论

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

评论(5

聚集的泪 2024-08-28 04:14:43

执行此操作的最佳方法是子类化 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

The best way to do this is to subclass String and redefine the comparison operator to meet your needs. Then use your new class to make the range.

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

Now you can ensure that a column appears before another.

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

N.B.: Only the string on the left side of any comparison operator needs to be of class MyString:

MyString.new("b") < "aa" #=> true
"aa" > MyString.new("b") #=> false
生寂 2024-08-28 04:14:43

看起来 Ruby 正在使用 succ,但首先它会检查 end>=start,并且由于这里的值是 false,因此它甚至不会尝试。

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

话又说回来,从这里的一些其他答案来看,它看起来在 Ruby 的某些版本中确实按照您的预期工作,所以也许它在 1.9 中得到了修复?

It looks like Ruby is using succ, but first it checks for end>=start, and since that is false here, it doesn't even try.

Admittedly String#succ is a weird beast here: a string's successor isn't always greater than the string, using its own comparison methods. So I'm not sure if this is technically a bug or not. It does look pretty confusing if you don't know this undocumented check, though.

Then again, judging by some of the other answers here, it looks like it does work as you expect in some versions of Ruby, so maybe it was fixed in 1.9?

我早已燃尽 2024-08-28 04:14:43

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


我想如果对于每个 a, b ,其中 b 最终由 a.succ.succ 生成,那就太好了。 .a <=> 也是如此。 b返回-1。这样做很好的一个原因是,实际上正是 <=>succ 用于首先实现范围。因此,正如您所注意到的,.succ 最终完成扩展的 Ruby String 范围不起作用,因为 <=> 测试与它相矛盾并终止了环形。

所以是的,<=> 定义的顺序(至少对于 String)与 #succ 方法顺序不匹配。这是一些开发人员避免使用 succ 的原因之一。

It is true that in class String, <=> and String#succ are not completely harmonized


I suppose it would be nice if for each a, b where b eventually is produced from a.succ.succ..., it was also true that a <=> b returned -1. One reason this would be nice is that it is in fact precisely <=> and succ that are used to implement ranges in the first place. Consequently, as you have noted, a Ruby String range where .succ would eventually complete the expansion doesn't work because a <=> test contradicts it and terminates the loop.

So yes, the ordering, at least for String, that is defined by <=> doesn't match the #succ method ordering. This is one reason that some developers avoid using succ.

温折酒 2024-08-28 04:14:43

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

This DOESN'T work in ruby 1.8.7 (2009-06-12 patchlevel 174) nor in ruby 1.9.1p376 (2009-12-07 revision 26041) [i486-linux]

“b”..“ba”确实有效...

irb(main):001:0> ("b".."ba").each {|x|打印“#{x}”}
bcdefghijklmnopqrstuv wxyz 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”

Any advice to make "b".."aa" work as expected in ruby ?

This DOESN'T work in ruby 1.8.7 (2009-06-12 patchlevel 174) nor in ruby 1.9.1p376 (2009-12-07 revision 26041) [i486-linux]

"b".."ba" does work...

irb(main):001: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"

小情绪 2024-08-28 04:14:43

此处将此报告为 Ruby 中的错误。结果取决于您运行的 Ruby 版本。版本 1.8.6 和 1.9.1 之间存在差异。

This was reported as a bug in Ruby here. The results depend on which version of Ruby you are running. There is a difference between versions 1.8.6 and 1.9.1.

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