Ruby: Cách chuyển đổi một chuỗi thành boolean


107

Tôi có một giá trị sẽ là một trong bốn thứ: boolean true, boolean false, chuỗi "true" hoặc chuỗi "false". Tôi muốn chuyển đổi chuỗi thành boolean nếu nó là một chuỗi, nếu không thì hãy để nó không sửa đổi. Nói cách khác:

"true" phải trở thành true

"false" phải trở thành false

đúng nên luôn đúng

sai nên vẫn sai


2
Kết quả phải là một trong hai giá trị truehay falseđủ nếu kết quả là true hoặc falsey? Nếu giá trị thứ hai, thì falseđã là false, và cả hai true'true'đều là true, vì vậy giá trị duy nhất mà kết quả chưa chính xác, là 'false': if input == 'false' then true else input endnên làm điều đó.
Jörg W Mittag,

Đó là một nhận xét tuyệt vời Jorg, tuy nhiên tôi sẽ giả định rằng đối với một số ứng dụng, cần phải có giá trị boolean đúng hoặc sai chứ không chỉ một giá trị là true hoặc false.
emery

2
Emery, nếu bạn cần phải trả lại một boolean bạn có thể thêm vào trước @ biểu Jörg với hai "nots": !!(if input == 'false' then true else input end). Giá trị thứ hai !chuyển đổi giá trị trả về thành boolean ngược lại với những gì bạn muốn; đầu tiên !sau đó thực hiện chỉnh sửa. "Thủ thuật" này đã có từ lâu. Không phải ai cũng thích nó.
Cary Swoveland

Câu trả lời:


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

3
Đúng, @null, phương thức to_s chuyển đổi boolean true hoặc false thành "true" hoặc "false" và giữ nguyên giá trị nếu ban đầu là một chuỗi. Bây giờ chúng ta chắc chắn có "true" hoặc "false" là một chuỗi ... và chúng ta chỉ cần sử dụng == kiểm tra xem chuỗi có bằng "true" hay không. Nếu đúng thì giá trị ban đầu là true hoặc "true". Nếu không phải thì giá trị ban đầu là false, "false" hoặc một cái gì đó hoàn toàn không liên quan.
emery

8
Vì chuỗi có thể được tăng / có tiêu đề, việc viết hoa giảm sẽ đảm bảo khớp:obj.to_s.downcase == 'true'
TDH

1
Sử dụng downcase!và bạn sẽ phân bổ bớt 1 đối tượng. downcasesẽ sao chép chuỗi hiện có. Khi Frozen String Literals trở thành một tùy chọn mặc định của Ruby, điều này sẽ ít quan trọng hơn.
danielricecodes

Tôi đã tự do chỉnh sửa câu trả lời để bao gồm gợi ý về chữ thường! theo các ý kiến ​​trên. Nó kém thanh lịch hơn để đọc, nhưng nếu bạn không chắc mình đang làm việc với loại biến nào, thì tính mạnh mẽ hơn không bao giờ là xấu.
emery

Đây wont thông báo lỗi nếu bạn ăn nó dữ liệu xấu, vì vậy nó không phải là một giải pháp tuyệt vời nếu bạn cần bất kỳ xử lý lỗi
Toby 1 Kenobi

118

Nếu bạn sử dụng Rails 5, bạn có thể làm được ActiveModel::Type::Boolean.new.cast(value).

Trong Rails 4.2, sử dụng ActiveRecord::Type::Boolean.new.type_cast_from_user(value).

Hành vi hơi khác một chút, như trong Rails 4.2, giá trị true và false được kiểm tra. Trong Rails 5, chỉ các giá trị false mới được kiểm tra - trừ khi các giá trị bằng không hoặc khớp với một giá trị false, nó được giả định là true. Giá trị sai giống nhau trong cả hai phiên bản: FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]

Rails 5 Nguồn: https://github.com/rails/rails/blob/5-1-stable/activemodel/lib/active_model/type/boolean.rb


1
Điều này rất hữu ích, mặc dù tôi ước rằng bộ FALSE_VALUEStrong Rails cũng bao gồm "không".
pjrebsch

3
@pjrebsch Bản vá trong ứng dụng của bạn khá đơn giản. Chỉ cần thêm ActiveRecord::Type::Boolean::FALSE_VALUES << "no"vào một trình khởi tạo.
thomasfedb

lưu ý rằng phân ActiveModel::Type::Boolean.new.cast(value)biệt chữ hoa chữ thường ... vì vậy 'False' sẽ đánh giá thành true cũng như bất kỳ chuỗi nào khác ngoại trừ 'false'. chuỗi rỗng ''mặc định là nil, không false. ^^ cái nhìn sâu sắc có giá trị cung cấp ở đây bởi @thomasfedb trên tùy initializer
frostini

1
ActiveModel::Type::Boolean.new.cast(nil)cũng trở lại nil.
Nikolay D

1
Kể từ Rails 5.2.4, phương thức do @thomasfedb gợi ý không còn hoạt động vì ActiveRecord::Type::Boolean::FALSE_VALUESbị đóng băng.
chuyển vào

24

Tôi đã thường xuyên sử dụng mẫu này để mở rộng hành vi cốt lõi của Ruby để giúp dễ dàng hơn trong việc chuyển đổi các kiểu dữ liệu tùy ý thành các giá trị boolean, điều này giúp bạn thực sự dễ dàng đối phó với các tham số URL khác nhau, v.v.

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

Vì vậy, giả sử bạn có một tham số foocó thể là:

  • một số nguyên (0 là sai, tất cả các số khác đều đúng)
  • một boolean đúng (true / false)
  • một chuỗi ("true", "false", "0", "1", "TRUE", "FALSE")
  • không

Thay vì sử dụng một loạt các điều kiện, bạn chỉ có thể gọi foo.to_booleanvà nó sẽ thực hiện phần còn lại của phép thuật cho bạn.

Trong Rails, tôi thêm nó vào một trình khởi tạo có tên core_ext.rbtrong gần như tất cả các dự án của tôi vì mẫu này rất phổ biến.

## 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

còn 't' và 'f' 'T' & 'F', 'y' & 'n', 'Y' & 'N' thì sao?
MrMesees 25/09/19

Điều này hoạt động quá tốt, ví dụ. "Mua" có bắt đầu bằng "b" không? "buy"=~/b/ => 0 Nhưng("buy"=~/b/).to_boolean => false
Marcos

23

Đừng suy nghĩ nhiều:

bool_or_string.to_s == "true"  

Vì thế,

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

Bạn cũng có thể thêm ".downcase" nếu bạn lo lắng về các chữ cái viết hoa.


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

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

10
Mã của bạn như một lớp lótvalue.to_s == 'true' ? true : false
Sagar Pandya

20
@ sagarpandya82: Đừng bao giờ làm điều đó, nó đánh bại mục đích của toán tử điều kiện: if true then true, if false then falseĐoán xem? Bạn hoàn toàn có thể loại bỏ nó! value.to_s == 'true' ? true : falsechỉ nên làvalue.to_s == 'true'
Eric Duminil

4
@EricDuminil hoàn toàn đồng ý, lỗi của tân binh vào thời điểm đó.
Sagar Pandya

2
Lưu ý rằng câu trả lời này sẽ trả về nil khi giá trị không thể được chuyển đổi trong khi những dấu một dòng đó sẽ không bao giờ bị lỗi và luôn trả về false trừ khi giá trị là 'true'. Cả hai đều là cách tiếp cận hợp lệ và có thể là câu trả lời đúng cho các tình huống khác nhau, nhưng chúng không giống nhau.
Doodad

1
@AndreFigueedlyo toán tử bậc ba không làm gì trong trường hợp này. Hãy thử mà không cần, và so sánh kết quả.
Eric Duminil

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

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

7

Trong một ứng dụng rails 5.1, tôi sử dụng phần mở rộng cốt lõi được xây dựng trên ActiveRecord::Type::Boolean. Nó đang hoạt động hoàn hảo cho tôi khi tôi giải mã boolean từ chuỗi 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

khởi tạo phần mở rộng cốt lõi

# 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

Đây là hoàn hảo. Chính xác những gì tôi đang tìm kiếm.
Doug

5

Trong Rails, tôi thích sử dụng ActiveModel::Type::Boolean.new.cast(value)như đã đề cập trong các câu trả lời khác ở đây

Nhưng khi tôi viết Ruby lib đơn giản. sau đó tôi sử dụng một bản hack trong đó JSON.parse(thư viện Ruby tiêu chuẩn) sẽ chuyển đổi chuỗi "true" thành truevà "false" thành false. Ví dụ:

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

Ví dụ từ ứng dụng trực tiếp:

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

được xác nhận theo Ruby 2.5.1


5

Làm việc trong 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... Sử dụng to_s.downcase trên đầu vào của bạn là một ý kiến ​​hay
Raphayol

4

Tôi có một chút hack cho cái này. JSON.parse('false')sẽ trở lại falseJSON.parse('true')sẽ trả về true. Nhưng điều này không hoạt động với JSON.parse(true || false). Vì vậy, nếu bạn sử dụng một cái gì đó giống như JSON.parse(your_value.to_s)nó sẽ đạt được mục tiêu của bạn một cách đơn giản nhưng khó hiểu.


3

Có thể sử dụng một gem như https://rubygems.org/gems/to_bool , nhưng nó có thể dễ dàng được viết thành một dòng bằng cách sử dụng regex hoặc ternary.

ví dụ regex:

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

ví dụ bậc ba:

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

Ưu điểm của phương pháp regex là biểu thức chính quy rất linh hoạt và có thể khớp với nhiều mẫu khác nhau. Ví dụ: nếu bạn nghi ngờ rằng var có thể là bất kỳ "True", "False", 'T', 'F', 't' hoặc 'f', thì bạn có thể sửa đổi regex:

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

2
Lưu ý: \A/ \z là đầu / cuối của chuỗi và ^/ $là đầu / cuối của dòng. Vì vậy, nếu var == "true\nwhatevs"sau đó boolean == true.
cremno

Điều này thực sự đã giúp tôi và tôi var.eql?('true') ? true : falserất thích . Cảm ơn!
Christian

3

Mặc dù tôi thích cách tiếp cận băm (trước đây tôi đã sử dụng nó cho những thứ tương tự), vì bạn chỉ thực sự quan tâm đến việc khớp các giá trị trung thực - vì - mọi thứ khác đều sai - bạn có thể kiểm tra để đưa vào một mảng:

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

hoặc nếu các giá trị khác có thể được coi là trung thực:

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

bạn phải làm những thứ khác nếu bản gốc của bạn valuecó thể là trường hợp hỗn hợp:

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

nhưng một lần nữa, đối với mô tả cụ thể về vấn đề của bạn, bạn có thể lấy ví dụ cuối cùng đó làm giải pháp cho mình.


2

Trong rails, trước đây tôi đã làm một việc như sau:

class ApplicationController < ActionController::Base
  # ...

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

  # ...
end

Thật tuyệt nếu bạn đang cố gắng so sánh các chuỗi boolean của mình theo cách giống như rails cho cơ sở dữ liệu của bạn.


0

Gần với những gì đã được đăng, nhưng không có tham số thừa:

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

sử dụng:

do_stuff = "true"

if do_stuff.true?
    #do stuff
end
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.