Ruby:如何将字符串转换为布尔值

Posted

技术标签:

【中文标题】Ruby:如何将字符串转换为布尔值【英文标题】:Ruby: How to convert a string to boolean 【发布时间】:2016-07-13 17:41:00 【问题描述】:

我有一个值,它将是以下四种情况之一:boolean true、boolean false、字符串“true”或字符串“false”。如果它是字符串,我想将字符串转换为布尔值,否则保持不变。换句话说:

“真”应该变成真

“假”应该变成假

真实应该保持真实

假应该保持假

【问题讨论】:

结果是否truefalse这两个值之一,或者如果结果为真或假就足够了吗?如果是后者,那么 false 已经是假的,true'true' 都是真值,所以结果不正确的唯一值是 'false': if input == 'false' then true else input end 应该这样做。 Jorg 的评论很棒,但是我认为对于某些应用程序来说,布尔值必须是真或假,而不仅仅是一个真假值。 Emery,如果你需要返回一个布尔值,你可以在 @Jörg 的表达式前面加上两个“not”:!!(if input == 'false' then true else input end)。第二个! 将返回值转换为与您想要的相反的布尔值;第一个! 然后进行更正。这个“把戏”由来已久。不是每个人都喜欢它。 【参考方案1】:
if value.to_s == 'true'
  true
elsif value.to_s == 'false'
  false
end

【讨论】:

您的代码作为单行代码value.to_s == 'true' ? true : false @sagarpandya82 :永远不要这样做,它违背了条件运算符的目的:if true then true, if false then false 你猜怎么着?您可以完全删除它! value.to_s == 'true' ? true : false 应该只是 value.to_s == 'true' @EricDuminil 绝对同意,当时的菜鸟错误。 请注意,当值无法转换时,此答案将返回 nil,而那些单行代码永远不会失败,并且始终返回 false,除非值为“真”。两者都是有效的方法,可能是不同情况的正确答案,但它们并不相同。 @AndreFigueiredo 在这种情况下,三元运算符不做任何事情。尝试不使用,然后比较结果。【参考方案2】:
h =  "true"=>true, true=>true, "false"=>false, false=>false 

["true", true, "false", false].map  |e| h[e] 
  #=> [true, true, false, false] 

【讨论】:

【参考方案3】:

可以使用像https://rubygems.org/gems/to_bool 这样的gem,但可以使用正则表达式或三进制轻松地将它写在一行中。

正则表达式示例:

boolean = (var.to_s =~ /^true$/i) == 0

三元示例:

boolean = var.to_s.eql?('true') ? true : false

正则表达式方法的优点是正则表达式很灵活,可以匹配多种模式。例如,如果您怀疑 var 可能是“True”、“False”、“T”、“F”、“t”或“f”中的任何一个,那么您可以修改正则表达式:

boolean = (var.to_s =~ /^[Tt].*$/i) == 0

【讨论】:

注意:\A/\z 是字符串的开始/结束,^/$ 是行的开始/结束。所以如果var == "true\nwhatevs" 那么boolean == true 这对我很有帮助,我非常喜欢var.eql?('true') ? true : false。谢谢! @Christian 记住它必须是 var.to_s.eql?不只是 var.eql?否则它不会将布尔值 true 转换为字符串 'true'【参考方案4】:
def true?(obj)
  obj.to_s.downcase == "true"
end

【讨论】:

是的,@null,to_s 方法将布尔值 true 或 false 转换为“true”或“false”,如果最初是字符串,则保持值不变。现在我们确定将“true”或“false”作为字符串......我们只需要使用 == 检查字符串是否等于“true”。如果是,则原始值为真或“真”。如果不是,则原始值为 false、“false”或完全不相关的内容。 由于字符串可能被大写/标题,小写将确保匹配:obj.to_s.downcase == 'true' 使用downcase! 你会少分配1个对象。 downcase 将复制现有字符串。当 Frozen String Literals 成为 Ruby 默认选项时,这将不再那么重要。 我冒昧地编辑了答案以包含小写的建议!根据上述cmets。阅读起来不太优雅,但如果你不确定你正在使用什么变量类型,那么更健壮性永远不会坏。 如果您输入错误数据,这不会报告错误,因此如果您需要任何错误处理,这不是一个很好的解决方案【参考方案5】:

虽然我喜欢哈希方法(我过去曾将它用于类似的东西),但考虑到您只关心匹配真实值 - 因为 - 其他所有内容都是错误的 - 您可以检查是否包含在数组中:

value = [true, 'true'].include?(value)

或者如果其他值可以被认为是真实的:

value = [1, true, '1', 'true'].include?(value)

如果您原来的 value 可能是大小写混合,您将不得不做其他事情:

value = value.to_s.downcase == 'true'

但同样,对于您对问题的具体描述,您可以使用最后一个示例作为您的解决方案。

【讨论】:

【参考方案6】:

在 Rails 中,我以前做过这样的事情:

class ApplicationController < ActionController::Base
  # ...

  private def bool_from(value)
    !!ActiveRecord::Type::Boolean.new.type_cast_from_database(value)
  end
  helper_method :bool_from

  # ...
end

如果您尝试以与 rails 对数据库相同的方式匹配布尔字符串比较,这很好。

【讨论】:

【参考方案7】:

如果你使用 Rails 5,你可以ActiveModel::Type::Boolean.new.cast(value)

在 Rails 4.2 中,使用 ActiveRecord::Type::Boolean.new.type_cast_from_user(value)

行为略有不同,如在 Rails 4.2 中,检查真值和假值。在 Rails 5 中,只检查 false 值 - 除非值是 nil 或匹配 false 值,否则假定为 true。两个版本中的 False 值相同: FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]

Rails 5 来源:https://github.com/rails/rails/blob/5-1-stable/activemodel/lib/active_model/type/boolean.rb

【讨论】:

这很有帮助,虽然我希望 Rails 中的 FALSE_VALUES 集合也包含“no”。 @pjrebsch 在你的应用中打补丁相当简单。只需将 ActiveRecord::Type::Boolean::FALSE_VALUES &lt;&lt; "no" 添加到初始化程序即可。 请注意,ActiveModel::Type::Boolean.new.cast(value) 区分大小写...所以 'False' 将与除 'false' 之外的任何其他字符串一样评估为 true。空字符串'' 默认为 nil,而不是 false。 ^^@thomasfedb 提供的关于初始化程序定制的宝贵见解 ActiveModel::Type::Boolean.new.cast(nil) 也返回 nil 从 Rails 5.2.4 开始,@thomasfedb 建议的方法不再有效,因为 ActiveRecord::Type::Boolean::FALSE_VALUES 已冻结。【参考方案8】:

我经常使用这种模式来扩展 Ruby 的核心行为,以便更轻松地将任意数据类型转换为布尔值,这使得处理各种 URL 参数等变得非常容易。

class String
  def to_boolean
    ActiveRecord::Type::Boolean.new.cast(self)
  end
end

class NilClass
  def to_boolean
    false
  end
end

class TrueClass
  def to_boolean
    true
  end

  def to_i
    1
  end
end

class FalseClass
  def to_boolean
    false
  end

  def to_i
    0
  end
end

class Integer
  def to_boolean
    to_s.to_boolean
  end
end

假设您有一个参数foo,它可以是:

一个整数(0 为假,其他为真) 一个真正的布尔值(真/假) 一个字符串(“真”、“假”、“0”、“1”、“真”、“假”) 无

您可以调用foo.to_boolean,而不是使用一堆条件,它会为您完成剩下的魔法。

在 Rails 中,我几乎在所有项目中都将它添加到名为 core_ext.rb 的初始化程序中,因为这种模式非常常见。

## EXAMPLES

nil.to_boolean     == false
true.to_boolean    == true
false.to_boolean   == false
0.to_boolean       == false
1.to_boolean       == true
99.to_boolean      == true
"true".to_boolean  == true
"foo".to_boolean   == true
"false".to_boolean == false
"TRUE".to_boolean  == true
"FALSE".to_boolean == false
"0".to_boolean     == false
"1".to_boolean     == true
true.to_i          == 1
false.to_i         == 0

【讨论】:

't' 和 'f' 'T' 和 'F'、'y' 和 'n'、'Y' 和 'N' 呢? 这很好用,例如。 “买”是否以“b”开头? "buy"=~/b/ =&gt; 0("buy"=~/b/).to_boolean =&gt; false【参考方案9】:

别想太多:

bool_or_string.to_s == "true"  

所以,

"true".to_s == "true"   #true
"false".to_s == "true"  #false 
true.to_s == "true"     #true
false.to_s == "true"    #false

如果您担心大写字母,也可以添加“.downcase”。

【讨论】:

nil.to_s == 'true' #false @juliangonzalez:这是我在所有其他解释中遗漏的事实 - 谢谢。【参考方案10】:

在一个 rails 5.1 应用程序中,我使用这个基于 ActiveRecord::Type::Boolean 构建的核心扩展。当我从 JSON 字符串反序列化布尔值时,它对我来说非常有效。

https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html

# app/lib/core_extensions/string.rb
module CoreExtensions
  module String
    def to_bool
      ActiveRecord::Type::Boolean.new.deserialize(downcase.strip)
    end
  end
end

初始化核心扩展

# config/initializers/core_extensions.rb
String.include CoreExtensions::String

rspec

# spec/lib/core_extensions/string_spec.rb
describe CoreExtensions::String do
  describe "#to_bool" do
    %w[0 f F false FALSE False off OFF Off].each do |falsey_string|
      it "converts #falsey_string to false" do
        expect(falsey_string.to_bool).to eq(false)
      end
    end
  end
end

【讨论】:

这是完美的。正是我想要的。【参考方案11】:

我对此有一点小窍门。 JSON.parse('false') 将返回 falseJSON.parse('true') 将返回 true。但这不适用于JSON.parse(true || false)。因此,如果您使用 JSON.parse(your_value.to_s) 之类的东西,它应该以一种简单但笨拙的方式实现您的目标。

【讨论】:

【参考方案12】:

在 Rails 中,我更喜欢使用ActiveModel::Type::Boolean.new.cast(value),正如此处其他答案中提到的那样

但是当我编写普通的 Ruby 库时。然后我使用JSON.parse(标准Ruby库)将字符串“true”转换为true和“false”转换为false的hack。例如:

require 'json'
azure_cli_response = `az group exists --name derrentest`  # => "true\n"
JSON.parse(azure_cli_response) # => true

azure_cli_response = `az group exists --name derrentesttt`  # => "false\n"
JSON.parse(azure_cli_response) # => false

来自实时应用的示例:

require 'json'
if JSON.parse(`az group exists --name derrentest`)
  `az group create --name derrentest --location uksouth`
end

在 Ruby 2.5.1 下确认

【讨论】:

【参考方案13】:

在 Rails 5 中工作

ActiveModel::Type::Boolean.new.cast('t')     # => true
ActiveModel::Type::Boolean.new.cast('true')  # => true
ActiveModel::Type::Boolean.new.cast(true)    # => true
ActiveModel::Type::Boolean.new.cast('1')     # => true
ActiveModel::Type::Boolean.new.cast('f')     # => false
ActiveModel::Type::Boolean.new.cast('0')     # => false
ActiveModel::Type::Boolean.new.cast('false') # => false
ActiveModel::Type::Boolean.new.cast(false)   # => false
ActiveModel::Type::Boolean.new.cast(nil)     # => nil

【讨论】:

ActiveModel::Type::Boolean.new.cast("False") # =&gt; true ... 在您的输入中使用 to_s.downcase 是个好主意 小心:ActiveModel::Type::Boolean.new.cast('fals') # =&gt; trueActiveModel::Type::Boolean.new.cast('falso') # =&gt; true【参考方案14】:

接近已经发布的内容,但没有多余的参数:

class String
    def true?
        self.to_s.downcase == "true"
    end
end

用法:

do_stuff = "true"

if do_stuff.true?
    #do stuff
end

【讨论】:

【参考方案15】:

Rubocop 建议格式:

YOUR_VALUE.to_s.casecmp('true').zero?

https://www.rubydoc.info/gems/rubocop/0.42.0/RuboCop/Cop/Performance/Casecmp

【讨论】:

我喜欢这个答案,因为它是一个处理原始问题中陈述的所有情况的单行代码,包括“true”和“false”中的大写与小写 T 和 F。与正则表达式不同,它不会自行处理“T”或“F”。唯一的批评者是“零”的用法?不熟悉该方法的人可能会感到困惑。【参考方案16】:

为简单起见,您可以使用eval。 请小心并避免过度使用 eval,因为它很容易成为安全风险。

eval('false') # => false
eval('true') # => true

更多关于评估:https://apidock.com/ruby/Kernel/eval

【讨论】:

以上是关于Ruby:如何将字符串转换为布尔值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用javascript将字符串数组转换为布尔值? [复制]

如何将字符串转换为布尔值

如何将“False”字符串转换为布尔值 false? [复制]

我们如何将字符串转换为布尔值? [复制]

使用 Freemarker 将字符串转换为布尔值

如何在 JavaScript 中将字符串转换为布尔值?