【问题标题】:Ruby: How to convert a string to booleanRuby:如何将字符串转换为布尔值
【发布时间】: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)。第二个! 将返回值转换为与您想要的相反的布尔值;第一个! 然后进行更正。这个“把戏”由来已久。不是每个人都喜欢它。

标签: ruby string boolean type-conversion


【解决方案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

              【讨论】:

                猜你喜欢
                • 2011-02-17
                • 2012-04-02
                • 2021-02-23
                • 1970-01-01
                • 2018-09-07
                • 1970-01-01
                • 2011-11-12
                • 2012-03-10
                相关资源
                最近更新 更多