为什么这个 Ruby if/else 循环运行不止一次,并且只在第二次运行部分



我正在创建一种方法来获取 Fixnum 输入并返回用单词拼写的数字。该方法在大多数情况下都有效,但是对于某些输入,我得到了一些古怪的输出。

当我窥探代码时,它似乎是这样一行代码:

# .concat(' hundred ').concat(reference.fetch(thousands%100)).concat(' thousand ')

它只是 if/else 语句的一部分,并且会自行运行两次。

111230.numbers_to_words()正确返回:"十万一千二百三十"

111130.numbers_to_words()错误返回:"十万一千一万一一百三十"

"十一万一千"是从已经成功运行的 if/else 语句返回的不需要的字符串元素。

这是怎么回事?我认为 if/else 语句一旦运行就无法再次处理。是什么原因导致那根神秘的字符串被退回?

class Fixnum
  define_method(:numbers_to_words) do
    remaining = self
    output = ""
    reference = { 1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five', 6 => 'six', 7 => 'seven', 8 => 'eight', 9 => 'nine',
                  10 => 'ten', 11 => 'eleven', 12 => 'twelve', 13 => 'thirteen', 14 => 'fourteen', 15 => 'fifteen', 16 => 'sixteen', 17 => 'seventeen',
                  18 =>  'eighteen', 19 => 'nineteen',
                  20 => 'twenty', 21 => 'twenty one', 22 => 'twenty two', 23 => 'twenty three', 24 => 'twenty four', 25 => 'twenty five', 26 => 'twenty six',
                  27 => 'twenty seven', 28 => 'twenty eight', 29 => 'twenty nine',
                  30 => 'thirty', 31 => 'thirty one', 32 => 'thirty two',
                  33 => 'thirty three', 34 => 'thirty four', 35 => 'thirty five', 36 => 'thirty six', 37 => 'thirty seven', 38 => 'thirty eight', 39 => 'thirty nine',
                  40 => 'forty', 41 => 'forty one', 42 => 'forty two', 43 => 'forty three', 44 => 'forty four', 45 => 'forty five', 46 => 'forty six', 47 => 'forty seven',
                  48 => 'forty eight', 49 => 'forty nine', 50 => 'fifty', 51 => 'fifty one', 52 => 'fifty two', 53 => 'fifty three', 54 => 'fifty four', 55 => 'fifty five',
                  56 => 'fifty six', 57 => 'fifty seven', 58 => 'fifty eight', 59 => 'fifty nine', 60 => 'sixty', 61 => 'sixty one', 62 => 'sixty two', 63 => 'sixty three',
                  64 => 'sixty four', 65 => 'sixty five', 66 => 'sixty six', 67 => 'sixty seven', 68 => 'sixty eight', 69 => 'sixty nine', 70 => 'seventy', 71 => 'seventy one',
                  72 => 'seventy two', 73 => 'seventy three', 74 => 'seventy four', 75 => 'seventy five', 76 => 'seventy six', 77 => 'seventy seven', 78 => 'seventy eight',
                  79 => 'seventy nine', 80 => 'eighty', 81 => 'eighty one', 82 => 'eighty two', 83 => 'eighty three', 84 => 'eighty four', 85 => 'eighty five',
                  86 => 'eighty six', 87 => 'eighty seven', 88 => 'eighty eight', 89 => 'eighty nine', 90 => 'ninety', 91 => 'ninety one', 92 => 'ninety two',
                  93 => 'ninety three', 94 => 'ninety four', 95 => 'ninety five', 96 => 'ninety six', 97 => 'ninety seven', 98 => 'ninety eight', 99 => 'ninety nine' }
    if remaining > 0 && remaining < 1000000000000
      if remaining >= 1000000000 && remaining < 1000000000000
        billions = remaining/1000000000
        remaining = remaining%1000000000
        if billions.to_s().length() > 2 && billions >= 100 && billions%100 != 0
          output = output + reference.fetch(billions/100).concat(' hundred ').concat(reference.fetch(billions%100)).concat(' billion ')
        elsif billions.to_s().length() > 2 && billions >= 100
          output = output.concat(reference.fetch(billions/100)).concat(' hundred ').concat(' billion ')
        elsif billions.to_s().length() < 3 && billions > 0 && billions < 100
          output = output.concat(reference.fetch(billions)).concat(' billion ')
        else
          output = output + " "
        end
      end
      if remaining >= 1000000 && remaining < 1000000000
        millions = remaining/1000000
        remaining = remaining%1000000
        if millions.to_s().length() > 2 && millions >= 100 && millions%100 != 0
          output = output + reference.fetch(millions/100).concat(' hundred ').concat(reference.fetch(millions%100)).concat(' million ')
        elsif millions.to_s().length() > 2 && millions >= 100
          output = output.concat(reference.fetch(millions/100)).concat(' hundred ').concat(' million ')
        elsif millions.to_s().length() < 3 && millions > 0 && millions < 100
          output = output.concat(reference.fetch(millions)).concat(' million ')
        else
          output = output + " "
        end
      end
      if remaining >= 1000 && remaining < 1000000 #111110
        thousands = remaining/1000 #111 length is 3
        remaining = remaining%1000 #110
        if thousands.to_s().length() > 2 && thousands >= 100 && thousands%100 == 0
        output = output + reference.fetch(thousands/100).concat(' hundred ').concat(' thousand ')
        elsif thousands.to_s().length() > 2 && thousands >= 100 && thousands%100 != 0
          output = output + reference.fetch(thousands/100).concat(' hundred ').concat(reference.fetch(thousands%100)).concat(' thousand ')
        elsif thousands.to_s().length() < 3 && thousands > 0 && thousands < 100
          output = output.concat(reference.fetch(thousands)).concat(' thousand ')
        else
          output = output + " "
        end
      end
      # .concat(' hundred ').concat(reference.fetch(thousands%100)).concat(' thousand ')
      if remaining >=100 && remaining < 1000
        if remaining>100 && remaining<1000 && remaining%100 > 0
          output = output + reference.fetch(remaining/100).concat(' hundred ').concat(reference.fetch(remaining%100))
        elsif remaining>100 && remaining<1000 && remaining%100 == 0
          output = output + reference.fetch(remaining/100).concat(' hundred ')
        elsif remaining == 100
          output = output + ('one hundred')
        else
          output = output + " "
        end
      end
      if remaining < 100 && remaining > 0
        output = output.concat(reference.fetch(remaining))
      end
    else
      output = "zero"
    end
    output.strip().squeeze(" ")
  end
end

问题是表单的所有行

reference.fetch(something).concat(" something else")

concat修改接收器(而不是返回新字符串),因此所有这些行都在更改reference哈希中的值。在某些情况下,您不会多次使用哈希中的任何值,因此您不会注意到问题,在其他情况下您会注意到问题。

将该用法替换为

reference.fetch(something) + "something else"

会避免这种情况

您可以考虑冻结哈希中的字符串 - 这将导致此类错误引发异常,而不是静默地行为不端。

最新更新