【问题标题】:Ruby implementation is_numeric? for Strings, need better alternativesRuby 实现 is_numeric?对于字符串,需要更好的替代品
【发布时间】:2009-08-17 08:54:39
【问题描述】:

我想验证字符串的“数值”(它不是活动记录模型中的属性)。我只需要它是一个有效的以 10 为底的正整数字符串。我正在这样做:

class String
  def numeric?
    # Check if every character is a digit
    !!self.match(/\A[0-9]+\Z/)
  end
end

class String
  def numeric?
    # Check is there is *any* non-numeric character
    !self.match(/[^0-9]/)
  end
end

以下哪一个是更合理的选择?或者,还有其他更好的实现方式吗?

【问题讨论】:

  • 出于好奇,为什么要使用 {1,1} 乘数?默认情况下,所有字符类和文字只匹配一次,除非另有说明。这是多余的。
  • 可怜的我!我会立即删除它。

标签: ruby string numerical


【解决方案1】:

请确保使用\A\Z 而不是^$,以匹配整个字符串而不是字符串中的单行。如果要避免将字符串与结束换行符匹配,请在末尾使用 '\z'。更多问题请见The Regex Tutorial on anchors

例如,/^[0-9]+$/ 成功匹配以下内容:

foo
1234
bar

/\A[0-9]+\Z/ 没有。

【讨论】:

    【解决方案2】:

    第一个对我来说看起来很正常。

    不过,我将方法命名为 numeric?。我不是is_foo? 方法的忠实粉丝。它们在方法名称中没有问号的语言中是有意义的(is_fooisFoo),但有了问号,is 就显得多余了。

    【讨论】:

    • 我最终使用了第二个。
    【解决方案3】:

    我不是 100% 确定,但 Rails 似乎使用 /\A[+-]?\d+\Z/ 表示整数。
    点击validates_numericality_ofhere的显示源

    【讨论】:

    • \A -> 字符串开头 \Z -> 字符串结尾 基本上和我在第一个中取消的一样,除了正/负修饰符部分。
    【解决方案4】:

    我会建议另一种方法。另外,因为你问的是“正”整数,所以我为正整数和非负整数分别做了两种方法。

    class String
      def numeric?
        !self.match(/[^0-9]/)
      end
    
      def positive_integer?
        self.to_i > 0
      end
    
      def nonnegative_integer?
        self.to_i > 0 or self == '0'
      end
    end
    

    这是基准代码:

    require 'benchmark'
    include Benchmark
    
    bmbm(100) do |x|
      x.report('numeric?') do
        "some invalid string".numeric?
      end
    
      x.report('positive_integer?') do
        "some invalid string".positive_integer?
      end
    
      x.report('nonnegative_integer?') do
        "some invalid string".nonnegative_integer?
      end
    end
    

    结果:

    numeric?
    0.000000   0.000000   0.000000 (  0.000045)
    positive_integer?
    0.000000   0.000000   0.000000 (  0.000012)
    nonnegative_integer?
    0.000000   0.000000   0.000000 (  0.000015)
    

    在这个微基准测试中,positive_integer?nonnegative_integer? 似乎更快。

    最后,附带说明一下,您可以用类似的方式定义integer? 方法:

    class String
      def integer?
        self.to_i.to_s == self
      end
    end
    

    【讨论】:

      【解决方案5】:

      对于非数字字符串,第二个会更快完成,因为它会拒绝第一个坏字符。

      另外,请查看 String#to_i 方法 - 它可能会执行您想要的操作:
      http://www.ruby-doc.org/core/classes/String.html#M000787

      【讨论】:

      • to_i 的问题是你永远不知道它是 0 还是不是数字。
      【解决方案6】:

      我不知道这是否很快,但我喜欢:

      class String
       def numeric?
          true if Integer(object) rescue false
       end
      end
      

      也处理负数。如果您将来想支持浮点数,只需使用 Float()

      【讨论】:

      • 这真的有效吗? object 来自哪里?在我的 ruby​​ 1.9.2-p180 上,它总是返回 false,因为 object 是未定义的。
      • 我认为在这种情况下object 应该是self
      【解决方案7】:

      根据一个简单的基准,第二种方法更快,虽然我不是专家基准,所以这可能不是一个有效的基准: http://pastie.org/586777

      Zalus 的逻辑是正确的。它只需要检查一次无效字符串。

      【讨论】:

        【解决方案8】:

        通知

        n = '1234'
        n.to_i.to_s == n
        => true
        
        n2 = '1.3'
        n.to_i.to_s == n2
        => false
        

        适用于正整数和负整数,但不适用于八进制/十六进制表示、浮点数等。性能可能不是最好的(未经测试),但过早的优化不会浪费时间。

        【讨论】:

          猜你喜欢
          • 2017-10-07
          • 1970-01-01
          • 1970-01-01
          • 2021-06-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-05
          • 2012-04-02
          相关资源
          最近更新 更多