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


107

我的值将是以下四项之一:布尔值true,布尔值false,字符串“ true”或字符串“ false”。我想将字符串转换为布尔值(如果是字符串),否则将其保持不变。换一种说法:

“真实”应变为真实

“假”应该变成假

true应该保持true

错误应保持错误


2
是否结果必须是这两个值中的一个truefalse抑或是不够的,如果结果是truthy或falsey?如果是后者,则false是已经falsey,都true'true'都truthy,所以其结果是不正确的话是唯一的价值'false'if input == 'false' then true else input end应该这样做。
约尔格W¯¯米塔格

对于Jorg来说,这是一个很棒的评论,但是我认为对于某些应用程序,必须使布尔值为true或false,而不仅仅是真或假的值。
2015年

2
埃默里(Emery),如果需要返回布尔值,可以在@Jörg的表达式前加上两个“ nots” :!!(if input == 'false' then true else input end)。第二个!将返回值转换为与您想要的相反的布尔值。第一个!然后进行更正。这个“把戏”已经存在了很长时间。并非每个人都喜欢它。
卡里·斯沃夫兰

Answers:


126
def true?(obj)
  obj.to_s.downcase == "true"
end

3
是的,@ null,to_s方法将布尔值true或false转换为“ true”或“ false”,并且如果最初是字符串则将值保持不变。现在我们确定字符串为“ true”或“ false” ...,我们只需要使用==检查字符串是否等于“ true”。如果是,则原始值为true或“ true”。如果不是,则原始值为false,“ false”或完全不相关的值。
金刚砂粉

8
由于字符串可能是大写/有标题的,因此小写将确保匹配:obj.to_s.downcase == 'true'
TDH

1
使用downcase!,您将少分配1个对象。 downcase将复制现有字符串。当Frozen String Literals成为Ruby的默认选项时,这将变得无关紧要。
danielricecodes

我自由地编辑答案以包含小写字母的建议!按照上面的评论。阅读起来不太优雅,但是如果您不确定要使用的变量类型,那么增强鲁棒性就永远不是坏事。
金刚砂

如果您向它提供错误的数据,这不会报告错误,因此,如果您需要任何错误处理,这不是一个很好的解决方案
Toby 1 Kenobi,

118

如果您使用Rails 5,则可以这样做ActiveModel::Type::Boolean.new.cast(value)

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

行为略有不同,例如在Rails 4.2中,将检查true值和false值。在Rails 5中,仅检查错误的值-除非值是nil或与错误的值匹配,否则假定它为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


1
这很有用,尽管我希望FALSE_VALUESin Rails 的集合中也包含“ no”。
pjrebsch

3
@pjrebsch在应用程序中进行修补非常简单。只需添加ActiveRecord::Type::Boolean::FALSE_VALUES << "no"到初始化程序即可。
thomasfedb

请注意,这ActiveModel::Type::Boolean.new.cast(value)是区分大小写的,因此'False'的计算结果为true,除'false'以外的其他任何字符串也将计算为true。空字符串''默认为nil,而不是false。^^ @thomasfedb在此处提供有关初始化程序自定义的宝贵见解
frostini

1
ActiveModel::Type::Boolean.new.cast(nil)也返回nil
Nikolay D

1
从Rails 5.2.4开始,@ thomasfedb建议的方法由于ActiveRecord::Type::Boolean::FALSE_VALUES冻结而不再起作用。
Moveson

24

我经常使用这种模式来扩展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为假,所有其他为真)
  • 真布尔值(真/假)
  • 字符串(“ true”,“ false”,“ 0”,“ 1”,“ TRUE”,“ FALSE”)

您可以调用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”呢?
MrMesees

这工作得很好,例如。“购买”是否以“ b”开头?"buy"=~/b/ => 0 但是("buy"=~/b/).to_boolean => false
Marcos

23

不要想太多:

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”。


5
nil.to_s == 'true' #false
juliangonzalez

15
if value.to_s == 'true'
  true
elsif value.to_s == 'false'
  false
end

10
您的单行代码value.to_s == 'true' ? true : false
Sagar Pandya

20
@ sagarpandya82:永远不要这样做,它违反了条件运算符的目的:你if true then true, if false then false猜怎么着?您可以将其完全删除!value.to_s == 'true' ? true : false应该只是value.to_s == 'true'
Eric Duminil '16

4
@EricDuminil绝对同意,当时菜鸟出错。
Sagar Pandya

2
请注意,当无法转换该值时,该答案将返回nil,而那些单行将永不失败,并且除非该值为'true',否则始终返回false。两者都是有效的方法,可能是针对不同情况的正确答案,但是它们并不相同。
Doodad

1
@AndreFigueiredo在这种情况下三元运算符不执行任何操作。尝试不使用,然后比较结果。
埃里克·杜米尼尔

13
h = { "true"=>true, true=>true, "false"=>false, false=>false }

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

7

在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

规格

# 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

太棒了。正是我想要的。
道格

5

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

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

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中得到确认


5

在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

1
ActiveModel::Type::Boolean.new.cast("False") # => true...在输入中使用to_s.downcase是个好主意
Raphayol

4

我对此有一点技巧。JSON.parse('false')将返回falseJSON.parse('true')返回true。但这不适用于JSON.parse(true || false)。因此,如果您使用类似的工具,JSON.parse(your_value.to_s)则应该以一种简单但却很简单的方式实现您的目标。


3

可以使用https://rubygems.org/gems/to_bool之类的gem ,但可以使用正则表达式或三进制轻松将其编写为一行。

正则表达式示例:

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

三元示例:

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

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

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

2
注意:\A/ \z 是字符串的开始/结尾,^/ $是行的开始/结尾。所以如果var == "true\nwhatevs"那么boolean == true
cremno

这确实帮助了我,我var.eql?('true') ? true : false非常喜欢。谢谢!
基督教徒

3

尽管我喜欢哈希方法(我过去曾在类似的东西上使用过它),但是由于您只真正关心匹配真实值-因为-其他所有内容都是假的-您可以检查是否包含在数组中:

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

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

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

如果您的原创作品,您还必须做其他事情 value可能是混合大小写,:

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

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


2

在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对数据库相同的方式来匹配布尔字符串比较,那就很好了。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.