将字符串“true”和“false”转为布尔值
Posted
技术标签:
【中文标题】将字符串“true”和“false”转为布尔值【英文标题】:String "true" and "false" to boolean 【发布时间】:2011-12-28 12:44:15 【问题描述】:我有一个 Rails 应用程序,我正在使用 jQuery 在后台查询我的搜索视图。有字段q
(搜索词)、start_date
、end_date
和internal
。 internal
字段是一个复选框,我正在使用 is(:checked)
方法构建被查询的 url:
$.getScript(document.URL + "?q=" + $("#search_q").val() + "&start_date=" + $("#search_start_date").val() + "&end_date=" + $("#search_end_date").val() + "&internal=" + $("#search_internal").is(':checked'));
现在我的问题出在params[:internal]
,因为有一个包含“true”或“false”的字符串,我需要将其转换为布尔值。我当然可以这样做:
def to_boolean(str)
return true if str=="true"
return false if str=="false"
return nil
end
但我认为必须有一种更 Ruby'ish 的方式来处理这个问题!那里没有……?
【问题讨论】:
【参考方案1】:据我所知,没有内置的将字符串转换为布尔值的方法,
但如果您的字符串仅由 'true'
和 'false'
组成,您可以将您的方法缩短为以下内容:
def to_boolean(str)
str == 'true'
end
【讨论】:
稍作修改 str == 'true' || str = '1' 也许 str.downcase == 'true' 为了完整性 @AMTourky 不应该是 str == 'true' || str == '1' 带有两个 "==" ? @Lowryder 是的!如果使用默认复选框。【参考方案2】:ActiveRecord 提供了一种干净的方式来执行此操作。
def is_true?(string)
ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(string)
end
ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES
将所有明显的 True 值表示为字符串。
【讨论】:
更简单,只需使用ActiveRecord::ConnectionAdapters::Column.value_to_boolean(string)
(来源)apidock.com/rails/v3.0.9/ActiveRecord/ConnectionAdapters/Column/…
是的,在最新版本中!
ActiveRecord::Type::Boolean.new.type_cast_from_user("true")
=> 真 ActiveRecord::Type::Boolean.new.type_cast_from_user("T")
=> 真
假值列表已移至 Rails 5 中的 ActiveModel::Type::Boolean
ActiveModel::Type::Boolean
似乎是一条更合适的路径 - 虽然 ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES
包含“真实”值,但有人可能会争辩说这只是偶然的情况,并且对于该特定值应该被视为真实的值可以包括用例,但不能包括其他用例。另一方面,ActiveModel::Type::Boolean
显然被设计为以通用方式使用。【参考方案3】:
安全通知
请注意,此答案仅适用于下面列出的其他用例,而不适用于问题中的用例。虽然大部分是固定的,但有许多 YAML related security vulnerabilities 是由将用户输入加载为 YAML 引起的。
我用来将字符串转换为布尔值的技巧是YAML.load
,例如:
YAML.load(var) # -> true/false if it's one of the below
YAML bool 接受相当多的真/假字符串:
y|Y|yes|Yes|YES|n|N|no|No|NO
|true|True|TRUE|false|False|FALSE
|on|On|ON|off|Off|OFF
另一个用例
假设你有一段这样的配置代码:
config.etc.something = ENV['ETC_SOMETHING']
在命令行中:
$ export ETC_SOMETHING=false
现在由于ENV
vars 是代码中的字符串,config.etc.something
的值将是字符串"false"
,它会错误地计算为true
。但如果你这样做:
config.etc.something = YAML.load(ENV['ETC_SOMETHING'])
一切都会好的。这也与从 .yml 文件加载配置兼容。
【讨论】:
如果传递的字符串在您的控制之下,那就太好了。在这个问题的情况下,提供的值来自用户的浏览器,因此,它们应该被认为是不安全的。 YAML 允许您序列化/反序列化任何 Ruby 对象,这有潜在的危险。发生了很多事件:google.com/webhp?q=rails+yaml+vulnerability @Teoulas,我完全同意你的看法。事实上,我正在添加一个通知,这样人们就不会以不安全的方式使用它。【参考方案4】:没有任何内置的方法来处理这个问题(尽管 actionpack 可能有一个帮助器)。我会建议这样的事情
def to_boolean(s)
s and !!s.match(/^(true|t|yes|y|1)$/i)
end
# or (as Pavling pointed out)
def to_boolean(s)
!!(s =~ /^(true|t|yes|y|1)$/i)
end
同样有效的方法是使用 0 和非 0 代替 false/true 文字:
def to_boolean(s)
!s.to_i.zero?
end
【讨论】:
如果你使用 "!!(s =~ /regex_here/)",则不需要保护 "s and ...",因为 "nil =~ /anything/" 返回 nil。 确实如此。我添加了它,但也保留了旧的,因为我认为.match
更容易阅读。【参考方案5】:
ActiveRecord::Type::Boolean.new.type_cast_from_user
根据 Rails 的内部映射 ConnectionAdapters::Column::TRUE_VALUES
和 ConnectionAdapters::Column::FALSE_VALUES
执行此操作:
[3] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("true")
=> true
[4] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("false")
=> false
[5] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("T")
=> true
[6] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("F")
=> false
[7] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("yes")
DEPRECATION WARNING: You attempted to assign a value which is not explicitly `true` or `false` ("yes") to a boolean column. Currently this value casts to `false`. This will change to match Ruby's semantics, and will cast to `true` in Rails 5. If you would like to maintain the current behavior, you should explicitly handle the values you would like cast to `false`. (called from <main> at (pry):7)
=> false
[8] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("no")
DEPRECATION WARNING: You attempted to assign a value which is not explicitly `true` or `false` ("no") to a boolean column. Currently this value casts to `false`. This will change to match Ruby's semantics, and will cast to `true` in Rails 5. If you would like to maintain the current behavior, you should explicitly handle the values you would like cast to `false`. (called from <main> at (pry):8)
=> false
因此,您可以在这样的初始化程序中创建自己的 to_b
(或 to_bool
或 to_boolean
)方法:
class String
def to_b
ActiveRecord::Type::Boolean.new.type_cast_from_user(self)
end
end
【讨论】:
它是 Rails 5 中的 ActiveRecord::Type::Boolean.new.cast(value)(参见下面的 CWitty)【参考方案6】:您可以使用wannabe_bool gem。 https://github.com/prodis/wannabe_bool
此 gem 为 String、Integer、Symbol 和 NilClass 类实现了 #to_b
方法。
params[:internal].to_b
【讨论】:
【参考方案7】:在 Rails 5 中,您可以使用 ActiveRecord::Type::Boolean.new.cast(value)
将其转换为布尔值。
【讨论】:
请注意,ActiveRecord::Type::Boolean.new.cast("42") 返回 true【参考方案8】:为了完整起见,可能是str.to_s.downcase == 'true'
。那么即使str
为 nil 或 0,也不会崩溃。
【讨论】:
【参考方案9】:我不认为 Ruby 内置了类似的东西。您可以重新打开 String 类并在那里添加 to_bool 方法:
class String
def to_bool
return true if self=="true"
return false if self=="false"
return nil
end
end
然后你可以在项目的任何地方使用它,像这样:params[:internal].to_bool
【讨论】:
我绝对不想让to_bool
函数返回nil
;这似乎是错误的。其他转换函数不这样做:"a".to_i
返回0
,而不是nil
【参考方案10】:
查看Virtus的源代码,我可能会这样做:
def to_boolean(s)
map = Hash[%w[true yes 1].product([true]) + %w[false no 0].product([false])]
map[s.to_s.downcase]
end
【讨论】:
【参考方案11】:您可以考虑仅将internal
附加到您的网址(如果它为真),那么如果未选中复选框并且您不附加它params[:internal]
将是nil
,它在Ruby 中的计算结果为假。
我对您使用的特定 jQuery 不是很熟悉,但是有没有比手动构建 URL 字符串更简洁的方法来调用您想要的内容?你看过$get
和$ajax
吗?
【讨论】:
【参考方案12】:您可以添加到 String 类以具有 to_boolean 的方法。然后你可以做 'true'.to_boolean 或 '1'.to_boolean
class String
def to_boolean
self == 'true' || self == '1'
end
end
【讨论】:
【参考方案13】:我很惊讶没有人发布这个简单的解决方案。也就是说,如果您的字符串将是“真”或“假”。
def to_boolean(str)
eval(str)
end
【讨论】:
那是因为这个解决方案是一个安全灾难。 :D 这个解决方案的问题是用户输入 - 如果有人输入to_boolean("ActiveRecord::Base.connection.execute('DROP TABLE *')")
,它会破坏你的数据库(并返回真!)。玩得开心:D
好点。我没有考虑上下文。我在想最少数量的字符来实现。 :)
上述漏洞的简单修复:bool = nil; bool = eval(str) if ["true", "false"].include?(str)
只是想为了澄清起见我应该添加。以上是关于将字符串“true”和“false”转为布尔值的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript - 使用JSON.parse()方法将字符串的‘false‘和‘true‘转换成布尔值
Pandas 映射到 TRUE/FALSE 作为字符串,而不是布尔值