Ruby: วิธีแปลงสตริงเป็นบูลีน


108

ฉันมีค่าที่จะเป็นหนึ่งในสี่สิ่ง ได้แก่ บูลีนจริงบูลีนเท็จสตริง "จริง" หรือสตริง "เท็จ" ฉันต้องการแปลงสตริงเป็นบูลีนหากเป็นสตริงมิฉะนั้นปล่อยให้ไม่มีการแก้ไข กล่าวอีกนัยหนึ่ง:

"จริง" ควรกลายเป็นจริง

"เท็จ" ควรกลายเป็นเท็จ

ความจริงควรเป็นจริง

เท็จควรเป็นเท็จ


2
ผลลัพธ์ต้องเป็นหนึ่งในสองค่าtrueหรือfalseหรือเพียงพอหรือไม่หากผลลัพธ์เป็นจริงหรือเท็จ ถ้าอย่างหลังแสดงว่าfalseเป็นเท็จอยู่แล้วและทั้งคู่trueและ'true'เป็นจริงดังนั้นค่าเดียวที่ผลลัพธ์ยังไม่ถูกต้องคือ'false': if input == 'false' then true else input endควรทำ
Jörg W Mittag

นั่นเป็นความคิดเห็นที่ยอดเยี่ยม Jorg อย่างไรก็ตามฉันคิดว่าสำหรับบางแอปพลิเคชันจำเป็นต้องมีค่าบูลีนเป็นจริงหรือเท็จและไม่ใช่แค่ค่าที่เป็นจริงหรือเท็จ
Emery

2
Emery ถ้าคุณต้องการที่จะกลับมาบูลคุณสามารถย่อหน้า @ แสดงออกJörgกับสอง "nots" !!(if input == 'false' then true else input end)A: ประการที่สอง!แปลงค่าที่ส่งคืนเป็นบูลีนที่ตรงข้ามกับสิ่งที่คุณต้องการ ขั้นแรก!จากนั้นทำการแก้ไข "เคล็ดลับ" นี้มีมาช้านานแล้ว ทุกคนไม่ชอบมัน
Cary Swoveland

คำตอบ:


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

3
ใช่ @null เมธอด to_s จะแปลงบูลีนจริงหรือเท็จเป็น "จริง" หรือ "เท็จ" และไม่เปลี่ยนแปลงค่าหากเดิมเป็นสตริง ตอนนี้เรามั่นใจแล้วว่าจะมี "true" หรือ "false" เป็นสตริง ... และเราต้องใช้ == ตรวจสอบว่าสตริงนั้นเท่ากับ "true" หรือไม่ หากเป็นเช่นนั้นค่าดั้งเดิมจะเป็นจริงหรือ "จริง" หากไม่เป็นเช่นนั้นค่าดั้งเดิมจะเป็นเท็จ "เท็จ" หรือบางสิ่งที่ไม่เกี่ยวข้องโดยสิ้นเชิง
Emery

8
เนื่องจากสตริงอาจขึ้น / ตั้งชื่อได้การลดขนาดจะทำให้แน่ใจว่าตรงกัน:obj.to_s.downcase == 'true'
TDH

1
ใช้downcase!และคุณจะจัดสรรวัตถุน้อยลง 1 รายการ downcaseจะทำซ้ำสตริงที่มีอยู่ เมื่อ Frozen String Literals กลายเป็นตัวเลือกเริ่มต้นของ Ruby สิ่งนี้จะมีความสำคัญน้อยลง
danielricecodes

ฉันใช้เสรีภาพในการแก้ไขคำตอบเพื่อรวมคำแนะนำของ downcase! ตามความเห็นข้างบน. มันดูหรูหราน้อยกว่าที่จะอ่าน แต่ถ้าคุณไม่แน่ใจว่าคุณกำลังใช้งานตัวแปรประเภทใดความแข็งแกร่งที่มากขึ้นก็ไม่เลว
กากกะรุน

สิ่งนี้จะไม่รายงานข้อผิดพลาดหากคุณป้อนข้อมูลที่ไม่ดีดังนั้นจึงไม่ใช่ทางออกที่ดีหากคุณต้องการการจัดการข้อผิดพลาดใด ๆ
Toby 1 Kenobi

118

ถ้าคุณใช้ทางรถไฟ 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_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_VALUESใน Rails จะรวม "ไม่" ด้วย
pjrebsch

3
@pjrebsch ค่อนข้างง่ายในการแก้ไขในแอปของคุณ เพียงเพิ่มActiveRecord::Type::Boolean::FALSE_VALUES << "no"ในโปรแกรมเริ่มต้น
thomasfedb

โปรดทราบว่าActiveModel::Type::Boolean.new.cast(value)คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ ... ดังนั้น 'False' จะประเมินเป็นจริงเช่นเดียวกับสตริงอื่น ๆ ยกเว้น 'false' สตริงว่าง''เริ่มต้นเป็นศูนย์ไม่ใช่เท็จ ^^ ข้อมูลเชิงลึกที่มีค่าให้ไว้ที่นี่โดย @thomasfedb เกี่ยวกับการปรับแต่ง initializer
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 ฉันเพิ่มสิ่งนี้ลงใน initializer ที่มีชื่อ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

4
@EricDuminil เห็นด้วยอย่างยิ่งข้อผิดพลาดมือใหม่ในเวลานั้น
Sagar Pandya

2
โปรดทราบว่าคำตอบนี้จะคืนค่าเป็นศูนย์เมื่อไม่สามารถแปลงค่าได้ในขณะที่เส้นเดียวเหล่านั้นจะไม่ล้มเหลวและจะส่งคืนเท็จเสมอเว้นแต่ค่าจะเป็น 'จริง' ทั้งสองวิธีเป็นแนวทางที่ถูกต้องและอาจเป็นคำตอบที่ถูกต้องสำหรับสถานการณ์ที่แตกต่างกัน แต่ไม่เหมือนกัน
Doodad

1
@AndreFigueiredo ตัวดำเนินการ ternary ไม่ได้ทำอะไรในกรณีนี้ ลองโดยไม่ต้องและเปรียบเทียบผลลัพธ์
Eric Duminil


7

ในแอป rail 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

ลงตัวนี้ที่สุด สิ่งที่ฉันกำลังมองหา
Doug

5

ใน Rails ฉันชอบใช้ActiveModel::Type::Boolean.new.cast(value)ตามที่กล่าวไว้ในคำตอบอื่น ๆ ที่นี่

แต่เมื่อฉันเขียน Ruby lib. แล้วฉันจะใช้สับที่ JSON.parse(มาตรฐานทับทิมห้องสมุด) จะแปลงสตริง "จริง" เพื่อtrueและ "เท็จ" 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')จะกลับมาfalseและJSON.parse('true')จะกลับมาจริง JSON.parse(true || false)แต่ตอนนี้ไม่ได้ทำงานกับ ดังนั้นหากคุณใช้สิ่งที่ชอบJSON.parse(your_value.to_s)ควรบรรลุเป้าหมายด้วยวิธีที่เรียบง่าย แต่แฮ็ค


3

อัญมณีเช่นhttps://rubygems.org/gems/to_boolสามารถใช้ได้ แต่สามารถเขียนเป็นบรรทัดเดียวได้อย่างง่ายดายโดยใช้ regex หรือ ternary

ตัวอย่าง regex:

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

ตัวอย่าง ternary:

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

ข้อดีของเมธอด regex คือนิพจน์ทั่วไปมีความยืดหยุ่นและสามารถจับคู่รูปแบบได้หลากหลาย ตัวอย่างเช่นหากคุณสงสัยว่า var อาจเป็น "True" "False" "T" "F" "t" หรือ "f" คุณสามารถแก้ไข regex ได้ดังนี้

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

2
หมายเหตุ: \A/ \z is start / end of string and ^/ $is start / end of line. ดังนั้นหากแล้วvar == "true\nwhatevs" boolean == true
ฌาปนกิจ

สิ่งนี้ช่วยฉันได้จริงๆและฉันชอบ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

ในรางฉันเคยทำสิ่งนี้มาก่อน:

class ApplicationController < ActionController::Base
  # ...

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

  # ...
end

ซึ่งเป็นสิ่งที่ดีถ้าคุณพยายามจับคู่การเปรียบเทียบสตริงบูลีนในลักษณะเดียวกับรางสำหรับฐานข้อมูลของคุณ


0

ใกล้เคียงกับสิ่งที่โพสต์แล้ว แต่ไม่มีพารามิเตอร์ซ้ำซ้อน:

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

การใช้งาน:

do_stuff = "true"

if do_stuff.true?
    #do stuff
end
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.