Проблема сравнения строк и диапазонов - PullRequest
2 голосов
/ 15 февраля 2010

Это имеет смысл для таких вещей, как:

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"

должен производить: В, С, D, Е, F, G, Н, I, J, К, L, М, N, О, Р, Q, R, S, Т, 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 patchlevel 174) [i486-linux]
  • Linux 2.6.31-19-generic # 56-Ubuntu SMP Чт 28 января 01:26:53 UTC 2010 i686 GNU / Linux

Ответы [ 5 ]

1 голос
/ 15 февраля 2010

Лучший способ сделать это - создать подкласс 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
0 голосов
/ 15 февраля 2010

Это правда, что в классе String <=> и String # succ не полностью согласованы


Полагаю, было бы неплохо, если бы для каждого a, b , где b в конечном итоге было получено из a.succ.succ ... , это было бы также верно, что a <=> b вернул -1. Одна из причин, по которой это было бы неплохо, заключается в том, что на самом деле именно <=> и succ используются для реализации диапазонов в первую очередь. Следовательно, как вы заметили, диапазон Ruby String, где .succ в конечном итоге завершит расширение, не работает, потому что тест <=> противоречит ему и завершает цикл.

Так что да, порядок, по крайней мере для String, который определяется <=>, не соответствует порядку #succ метода. Это одна из причин, по которой некоторые разработчики избегают использования succ.

0 голосов
/ 15 февраля 2010

Какой-нибудь совет, чтобы заставить "b" .. "aa" работать как положено в ruby?

Это НЕ работает ни в ruby ​​1.8.7 (2009-06-12 patchlevel 174), ни в ruby ​​1.9.1p376 (2009-12-07 revision 26041) [i486-linux]


"б" .. "ба" работает ...

irb (основной): 001: 0> ("b" .. "ba"). Каждый {| x | печать "# {x}"} b c d e f g h i j kl m n o p q r s t u v w x y z a a a a a a a a a a a a a a a a a a a a a a a a a a a a ar, как и в текущем режиме, как a a az ba => "b" .. "ba"

0 голосов
/ 15 февраля 2010

Похоже, что Ruby использует succ, но сначала он проверяет на end>=start, и, поскольку это неверно, он даже не пытается.

По общему признанию String#succ странный зверь здесь: преемник строки не всегда больше, чем строка, используя свои собственные методы сравнения. Так что я не уверен, технически ли это ошибка или нет. Это действительно выглядит довольно запутанным если вы не знаете этот недокументированный чек.

Опять же, судя по некоторым другим ответам здесь, похоже, что он работает, как вы ожидаете, в некоторых версиях Ruby, поэтому, возможно, это было исправлено в 1.9?

0 голосов
/ 15 февраля 2010

Это было сообщено как ошибка в Ruby здесь . Результаты зависят от того, какую версию Ruby вы используете. Существует разница между версиями 1.8.6 и 1.9.1.

...