Как Ruby сравнивает строки семантической версии?

Я заметил неожиданное поведение при сравнении строк Ruby. Который я напишу ниже:

2.3.1 :011 >   '5.6' >= '5.5'
  => true
2.3.1 :012 >   '5.6' >= '5.7'
  => false
2.3.1 :013 >   '5.6' >= '5.6.1'
  => false
2.3.1 :014 >   '5.6' <= '5.6.1'
  => true
2.3.1 :016 >   '4.6.1' <= '5.6'
  => true
2.3.1 :017 >   '4.6.1' >= '5.6'
  => false

Я вижу онлайн в нескольких местах, которые люди используют Gem::Version.new() сравнить семантические версии. Это не то, что мой вопрос здесь, хотя. Может кто-нибудь объяснить мне, как Ruby может сравнивать строки семантической версии без помощи какой-либо библиотеки? Что происходит, когда я сравниваю две строки с числовыми операторами сравнения?

Из приведенных выше тестов, я думаю, я могу подтвердить, что это не просто сравнение значений ascii первых / последних символов каждой строки. Он также не использует длину строки в качестве основного сравнения, что я и ожидал.

2 ответа

Решение

Он проверяет порядковый номер каждого отдельного символа в строке. Он останавливается при первом несоответствии по одному и тому же индексу. Чем выше порядковый номер, тем "крупнее" персонаж. В основном это что-то вроде:

first_string.chars.map(&:ord) >= second_string.chars.map(&:ord)

Как указано в комментариях, это не приводит к естественному упорядочению, поэтому люди используют Gem::Version:

'11' > '9' # => false

Это сравнивает простые строки.

Для строк, где все символы одной строки находятся в начале второй строки... но где вторая строка имеет большую длину, более короткая строка считается меньше, чем.

В противном случае символы сравниваются один за другим до тех пор, пока символ в позиции "x" одной строки не станет равным символу в позиции "x" второй строки, и в этих случаях символ, ранее находящийся в буквенно-цифровой последовательности, считается менее чем,

'cat' < 'caterpillar' 
=> true

'cow' < 'caterpillar' 
=> false

Вы НЕ МОЖЕТЕ полагаться на это, чтобы дать вам правильное сравнение семантической версии, если номера версий превышают одну цифру... так

'5.10' >= '5.9'
=> false

(это не то, на что можно было бы надеяться)

Другие вопросы по тегам