Ruby: Bir dizeyi boole'ye dönüştürme


110

Dört şeyden biri olacak bir değere sahibim: boolean true, boolean false, "true" dizesi veya "false" dizesi. Bir dizge ise dizeyi boolean'a dönüştürmek, aksi takdirde değiştirmeden bırakmak istiyorum. Diğer bir deyişle:

"doğru" gerçek olmalı

"yanlış" yanlış olmalı

doğru doğru kalmalı

yanlış, yanlış kalmalı


2
Sonuç mu var iki değerden biri olmak trueveya falsesonuç truthy veya Falsey ise veya bu yeterli mi? İkincisi ise, falseFalsey zaten, ve her iki trueve 'true'sonuç, zaten doğru değil olduğu tek değer, böylece truthy şunlardır 'false': if input == 'false' then true else input endyapmalı.
Jörg W Mittag

Bu harika bir yorum Jorg, ancak bazı uygulamalar için boole değerinin doğru veya yanlış bir değer değil, doğru veya yanlış olması gerektiğini varsayıyorum.
zımpara

2
Emery, size iki "fakirler" ile Jörg ifadesine @ Önlerine olabilir bir boolean dönmek gerekirse: !!(if input == 'false' then true else input end). İkincisi !, dönüş değerini istediğiniz şeyin tersi olan bir boole'ye dönüştürür; ilk !sonra düzeltmeyi yapar. Bu "numara" uzun zamandır var. Herkes bundan hoşlanmaz.
Cary Swoveland

Yanıtlar:


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

3
Evet, @null, to_s yöntemi boolean true veya false değerini "true" ya da "false" değerine dönüştürür ve eğer başlangıçta bir dizeyse değeri değiştirmeden bırakır. Şimdi, dizge olarak "true" ya da "false" olduğundan eminiz ... ve sadece == dizgesinin "true" ya eşit olup olmadığını kontrol etmemiz gerekiyor. Öyleyse, orijinal değer ya doğru ya da "doğru" dur. Değilse, orijinal değer yanlış, "yanlış" veya tamamen ilgisiz bir şeydi.
emery

8
Dizi yükseltilmiş / başlıklı olabileceğinden, alt harf kullanımı bir eşleşme sağlayacaktır:obj.to_s.downcase == 'true'
TDH

1
Kullanın downcase!ve 1 tane daha az nesne ayıracaksınız. downcasemevcut dizeyi kopyalayacaktır. Frozen String Literals bir Ruby varsayılan seçeneği haline geldiğinde, bu daha az önemli olacaktır.
danielricecodes

Mütevazı durum önerisini dahil etmek için cevabı düzenleme özgürlüğünü kullandım! yukarıdaki yorumlara göre. Okumak daha az zariftir, ancak hangi değişken türleriyle çalıştığınızdan emin değilseniz, daha sağlamlık asla kötü değildir.
zımpara

Bu, kötü veri beslerseniz bir hata bildirmez, bu nedenle herhangi bir hata işlemeye ihtiyacınız varsa harika bir çözüm değildir
Toby 1 Kenobi

121

Rails 5 kullanıyorsanız, yapabilirsiniz ActiveModel::Type::Boolean.new.cast(value).

Rails 4.2'de kullanın ActiveRecord::Type::Boolean.new.type_cast_from_user(value).

Davranış biraz farklıdır, Rails 4.2'de olduğu gibi, gerçek değer ve yanlış değerler kontrol edilir. Rails 5'te, yalnızca yanlış değerler kontrol edilir - değerler sıfır değilse veya yanlış bir değerle eşleşmedikçe, doğru olduğu varsayılır. Yanlış değerler her iki sürümde de aynıdır: FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]

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


1
Bu yararlıdır, ancak keşke FALSE_VALUESRails'teki setin de "hayır" içermesini isterdim .
pjrebsch

3
@pjrebsch Uygulamanızda yama yapmak oldukça basit. Sadece ActiveRecord::Type::Boolean::FALSE_VALUES << "no"bir başlatıcıya ekleyin .
thomasfedb

bunun ActiveModel::Type::Boolean.new.cast(value)büyük / küçük harfe duyarlı olduğunu unutmayın ... bu nedenle 'False', 'false' dışındaki diğer dizeler gibi doğru olarak değerlendirilecektir. boş dizeler ''varsayılan olarak nil'dir, yanlış değildir. ^^ @thomasfedb tarafından başlatıcı özelleştirmesi hakkında değerli bilgiler sağlanmıştır
frostini

1
ActiveModel::Type::Boolean.new.cast(nil)ayrıca döner nil.
Nikolay D

1
Rails 5.2.4'ten itibaren @thomasfedb tarafından önerilen yöntem ActiveRecord::Type::Boolean::FALSE_VALUESdonmuş olduğu için artık çalışmamaktadır .
hareket

24

Keyfi veri türlerini boole değerlerine dönüştürmeyi kolaylaştırmak için Ruby'nin temel davranışını genişletmek için sık sık bu kalıbı kullandım, bu da değişken URL parametreleri vb. İle başa çıkmayı gerçekten kolaylaştırır.

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

Diyelim ki aşağıdaki gibi bir parametreniz foovar:

  • bir tam sayı (0 yanlıştır, diğerleri doğrudur)
  • gerçek bir boole (doğru / yanlış)
  • bir dize ("doğru", "yanlış", "0", "1", "DOĞRU", "YANLIŞ")
  • sıfır

Bir sürü koşullu ifade kullanmak yerine, sadece arayabilirsin foo.to_booleanve o sihrin geri kalanını senin için yapacak.

Rails'de, core_ext.rbbu model çok yaygın olduğu için bunu neredeyse tüm projelerimde adı geçen bir başlatıcıya ekliyorum .

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

peki ya 't' ve 'f' 'T' & 'F', 'y' & 'n', 'Y' ve 'N'?
MrMesees

Bu çok iyi çalışıyor, örneğin. "Satın al" a "b" ile mi başlıyor? "buy"=~/b/ => 0 Ama("buy"=~/b/).to_boolean => false
Marcos

23

Fazla düşünmeyin:

bool_or_string.to_s == "true"  

Yani,

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

Büyük harflerle ilgili endişeleriniz varsa ".downcase" de ekleyebilirsiniz.


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

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

10
Tek satırlık kodunuzvalue.to_s == 'true' ? true : false
buz ツ

20
@ sagarpandya82: Bunu asla yapmayın, koşullu işlecin amacını bozar: if true then true, if false then falseBil bakalım ne oldu? Tamamen kaldırabilirsiniz! value.to_s == 'true' ? true : falsesadece olmalıvalue.to_s == 'true'
Eric Duminil

4
@EricDuminil kesinlikle katılıyor, o zaman çaylak hatası.
buz ツ

2
Değer dönüştürülemediğinde bu cevabın nil döndüreceğini ve bu tek satırlılar hiçbir zaman başarısız olmayacağını ve değer 'true' olmadığı sürece her zaman false döndürdüğünü unutmayın. Her ikisi de geçerli yaklaşımlardır ve farklı durumlara doğru yanıt olabilirler, ancak bunlar aynı değildir.
Doodad

1
@AndreFigueiredo üçlü operatör bu durumda hiçbir şey yapmaz. Onsuz deneyin ve sonuçları karşılaştırın.
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

Bir raylar 5.1 uygulamasında, üzerine kurulu bu çekirdek uzantısını kullanıyorum ActiveRecord::Type::Boolean. JSON dizesinden boolean'ın serisini kaldırdığımda benim için mükemmel çalışıyor.

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

çekirdek uzantıları başlat

# 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

Bu harika. Tam olarak aradığım şey.
Doug

7

Raylarda Çalışma 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... Girişinizde to_s.downcase kullanmak iyi bir fikirdir
Raphayol

5

Rails'de ActiveModel::Type::Boolean.new.cast(value)buradaki diğer yanıtlarda belirtildiği gibi kullanmayı tercih ediyorum

Ama düz Ruby lib yazdığımda. daha sonra JSON.parse(standart Ruby kitaplığı) "true" dizesini "true" ya trueve "false" dizgisine dönüştüren bir hack kullanıyorum false. Örneğin:

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

Canlı uygulamadan örnek:

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

Ruby 2.5.1 kapsamında onaylandı


4

Bunun için ufak bir hack'im var. JSON.parse('false')dönecek falseve JSON.parse('true')doğru dönecektir. Ancak bu işe yaramıyor JSON.parse(true || false). Öyleyse, JSON.parse(your_value.to_s)bunun gibi bir şey kullanırsanız , hedefinize basit ama hileli bir şekilde ulaşmalısınız.


3

Https://rubygems.org/gems/to_bool gibi bir mücevher kullanılabilir, ancak bir normal ifade veya üçlü kullanılarak tek satırda kolayca yazılabilir.

normal ifade örneği:

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

üçlü örnek:

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

Normal ifade yönteminin avantajı, normal ifadelerin esnek olması ve çok çeşitli desenlerle eşleşebilmesidir. Örneğin, değişkenin "True", "False", "T", "F", "t" veya "f" olabileceğinden şüpheleniyorsanız, normal ifadeyi değiştirebilirsiniz:

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

2
Not: \A/ \z dizenin başlangıcı / bitişidir ve ^/ $satırın başlangıcı / bitişidir. Öyleyse var == "true\nwhatevs"öyleyse boolean == true.
cremno

Bu bana gerçekten yardımcı oldu ve var.eql?('true') ? true : falseçok hoşuma gitti. Teşekkürler!
Christian

3

Hash yaklaşımını sevmeme rağmen (bunu geçmişte benzer şeyler için kullandım), sadece doğru değerleri eşleştirmeyi gerçekten önemsediğiniz için - çünkü - diğer her şey yanlıştır - bir diziye dahil olup olmadığını kontrol edebilirsiniz:

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

veya diğer değerler doğru kabul edilebilirse:

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

orijinaliniz valuebüyük / küçük harf karışıksa başka şeyler yapmanız gerekir:

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

ama yine, sorununuzun özel açıklaması için, çözümünüz olarak o son örnekle kurtulabilirsiniz.


2

Raylarda daha önce şöyle bir şey yaptım:

class ApplicationController < ActionController::Base
  # ...

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

  # ...
end

Boolean dizeleri karşılaştırmalarınızı veritabanınız için rails ile aynı şekilde eşleştirmeye çalışıyorsanız, bu güzel.


0

Önceden nakledilene yakın, ancak yedek parametre olmadan:

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

kullanım:

do_stuff = "true"

if do_stuff.true?
    #do stuff
end
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.