【问题标题】:Strictly convert string to integer (or nil)严格将字符串转换为整数(或 nil)
【发布时间】:2014-09-18 18:11:52
【问题描述】:

对于网络编程,数字以字符串形式出现。但是to_i 会将"5abc" 转换为5"abc" 转换为0,这两个都是错误的答案。为了抓住这些,我写道:

def number_or_nil( s )
  number = s.to_i
  number = nil if (number.to_s != s)
  return number
end

有没有一种更简洁、更自然的方式来完成这种转换并检测字符串不是数字?

【问题讨论】:

  • ' 5 ' 应该是5nil
  • 问题不清楚。 to_i 有什么问题?什么是“这种转化”?
  • nil 是我所期望的,虽然我可以忍受 5。
  • '5.0''5.1' 怎么样?这些肯定是打算作为数字的,既然这就是你提出问题的方式,那么这些不应该也转换为整数吗?
  • 整数是我唯一关心的问题,谢谢。就个人而言,我觉得奇怪的是,“to_i”会愉快地只转换字符串的前导部分并愉快地将“abc”转换为零......但目前看起来这样做是出于毫无疑问的好理由.谢谢。

标签: ruby type-conversion


【解决方案1】:

使用整数(字符串)

如果字符串无法转换为整数,则会引发 ArgumentError 错误。

Integer('5abc') #=> ArgumentError: invalid value for Integer(): "5abc"
Integer('5') #=> 5

如果您希望在无法转换字符串时返回 nil 的行为,您仍然需要您的 number_or_nil 方法。

def number_or_nil(string)
  Integer(string || '')
rescue ArgumentError
  nil
end

你应该小心地从一个特定的异常中解救出来。一个简单的救援(例如“rescue nil”)将从任何继承自 StandardError 的错误中救援,并且可能会以您不期望的方式干扰您的程序的执行。 Integer() 将引发 ArgumentError,因此请指定。

如果您不想处理异常而只喜欢更短的 number_or_nil 版本,您可以利用隐式返回值并将其写为:

def number_or_nil(string)
  num = string.to_i
  num if num.to_s == string
end

number_or_nil '5' #=> 5
number_or_nil '5abc' #=> nil

这将按您期望的方式工作。

【讨论】:

  • 唯一需要注意的是Integer(nil)提升TypeError,所以Integer(string || '')更加一致。
  • 在哪里可以找到Integer(string) 的(官方)文档?据我所知,官方ruby Integer documentation中没有提及。
  • 官方文档可以在ruby-doc.org/core/Kernel.html#method-i-Integer找到。
  • 你可能想要指定基数 10 Integer('5', 10),否则如果你得到类似 Integer('08') 的东西,它会因为假设错误的基数而引发错误。
  • 现在是brainf*k 时间:Integer('0010') => 8 所以不 - 你不能只是给它一个字符串然后交叉手指希望最好,因为像前导零这样简单的东西就可以做到这一点方法假设您正在处理二进制数
【解决方案2】:

至少从 Ruby 2.6 开始,内核函数 Integer、Float 等接受 exception 关键字参数来完成这项工作:

> Integer('42', exception: false)
=> 42
> Integer('x42', exception: false)
=> nil
> Integer('x42')
ArgumentError (invalid value for Integer(): "x42")
> Integer('', exception: false)
=> nil
> Integer('')
ArgumentError (invalid value for Integer(): "")
> Integer(nil, exception: false)
=> nil
> Integer(' 42 ', exception: false)
=> 42
> Integer(' 4 2 ', exception: false)
=> nil

请注意,Integer 也会让您控制基数,这是 to_i 不支持的:

> '0xf'.to_i
=> 0
> Integer('0xf')
=> 15
> Integer('10', 8)
=> 8

指定基数时,基数前缀(0x... 等)必须一致(如果存在):

> Integer('0xf', 10)
=> ArgumentError(invalid value for Integer(): "0xf")
> Integer('0xf', 16)
=> 15
> Integer('f', 16)
=> 15

【讨论】:

    【解决方案3】:

    使用简单的正则表达式检查str 是否为整数。

    def number_or_nil(str)
       str.to_i if str[/^-?\d+$/] and str.line.size == 1
    end
    

    【讨论】:

    • 由于输入来自网络,您应该更改答案以期待多行内容。 str.to_i if str[/\A\d+\z/]
    • 负整数、空格?
    • 已修复。我的检查要求对整数、没有空格、没有换行符有严格的规则。
    猜你喜欢
    • 2011-12-10
    • 1970-01-01
    • 2016-01-03
    • 1970-01-01
    • 2012-07-15
    • 2012-02-09
    • 2012-02-21
    • 2010-12-31
    相关资源
    最近更新 更多