为什么这个 Ruby if/else 循环 运行 不止一次,而第二次只循环了一部分?

Why is this Ruby if/else loop running more than once, and only partially on the second time?

我正在创建一个方法来获取 Fixnum 输入并 return 用文字拼写出的数字。该方法在大多数情况下都有效,但对于某些输入,我会得到一些古怪的输出。

而当我窥探代码时,似乎是这行代码:

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

这只是 if/else 语句的一部分,并且 运行 自身被两次

111230.numbers_to_words() 正确 returns: "one hundred eleven thousand two hundred thirty"

但是

111130.numbers_to_words() 错误 returns: "one hundred eleven thousand one hundred eleven thousand hundred thirty"

"hundred eleven thousand " 是不需要的字符串元素,它是 return 从已经 运行 本身成功的 if/else 语句编辑的。

这是怎么回事?我以为 if/else 语句一次 运行 不能再处理了。是什么导致那个神秘的字符串被 returned?

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"

会避免这种情况

您可能会考虑冻结散列中的字符串 - 这会导致此类错误引发异常,而不是默默地行为不端。