字符串/范围比较问题
这对于诸如 : 之类的事情有意义,
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
执行此操作的最佳方法是子类化 String 并重新定义比较运算符以满足您的需求。然后使用您的新类来制作范围。
现在您可以确保一列出现在另一列之前。
注意:只有比较运算符左侧的字符串才需要属于 MyString 类:
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.
Now you can ensure that a column appears before another.
N.B.: Only the string on the left side of any comparison operator needs to be of class MyString:
看起来 Ruby 正在使用
succ
,但首先它会检查end>=start
,并且由于这里的值是 false,因此它甚至不会尝试。诚然,
String#succ
在这里是一个奇怪的野兽:字符串的后继并不总是大于字符串,使用它自己的比较方法。所以我不确定这在技术上是否是一个错误。它看起来确实相当混乱 如果您不知道这个未记录的检查的话。话又说回来,从这里的一些其他答案来看,它看起来在 Ruby 的某些版本中确实按照您的预期工作,所以也许它在 1.9 中得到了修复?
It looks like Ruby is using
succ
, but first it checks forend>=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?
确实,在 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
<=>
andsucc
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 usingsucc
.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”
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"
此处将此报告为 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.