Bir Ruby geçiş ifadesi (case… when) regex ve backreferences ile nasıl yazılır?


89

Normal ifadelerle eşleşmeyi kontrol etmek için bir Ruby vaka ifadesi yazabileceğimi biliyorum. Bununla birlikte, maç verilerini iade bildirimimde kullanmak istiyorum. Bu yarı sözde kod gibi bir şey:

foo = "10/10/2011"

case foo
    when /^([0-9][0-9])/
        print "the month is #{match[1]}"
    else
        print "something else"
end

Bunu nasıl başarabilirim?

Teşekkürler!


Sadece bir not: Yukarıdaki gibi basit bir durum için bir switch deyimi kullanmayacağımı anlıyorum, ancak bu yalnızca bir örnek. Gerçekte, elde etmeye çalıştığım şey, birçok potansiyel düzenli ifadenin çeşitli şekillerde yazılabilen bir tarih için eşleştirilmesi ve ardından bunu Ruby'nin Date sınıfı ile buna göre ayrıştırmaktır.


1
Ruby'nin Date.parse birçok tarih biçimini anlar. Bunu denediniz mi?
raine

Bu soruyu cevaplamasa da, Chronic gem'e bakmak isteyebilirsiniz ...
DGM

Yanıtlar:


156

En son normal ifade gruplarına yapılan başvurular her zaman sözde değişkenlerde saklanır $1 için $9:

case foo
when /^([0-9][0-9])/
    print "the month is #{$1}"
else
    print "something else"
end

$LAST_MATCH_INFOTüm MatchDatanesneye ulaşmak için sözde değişkeni de kullanabilirsiniz . Bu, adlandırılmış yakalamalar kullanılırken yararlı olabilir:

case foo
when /^(?<number>[0-9][0-9])/
    print "the month is #{$LAST_MATCH_INFO['number']}"
else
    print "something else"
end

1
@Yossi İplik güvenliği ile ilgili yorumlarınız için bir kaynağınız var mı? Ruby 1.8.7'de iş parçacığı için güvenli olduğunu gösteren bir deney yaptım! (Her saniyede bir normal ifadeyle eşleşen iş parçacığı - yerel eşleşmeler yıpranıyorsa irb'yi kontrol edin)
Joel

5
Normal ifadelerle yapılacak -1 $ değişkenleri, önünde dolar işareti olmasına rağmen global değildir.
Andrew Grimm

@AndrewGrimm Bunu işaret ettiğiniz için teşekkürler. Farkında değildim. Çok sayıda eski kodu değiştirmem gerekecek: - /
Yossi

Ayrıca yapabilirsiniz $1, $2... $9ya Regexp.last_match(1)rubocop tarafından önerildiği gibi
Edgar Ortega

6

İşte size aynı sonucu veren ancak bir anahtar kullanmayan alternatif bir yaklaşım. Normal ifadelerinizi bir diziye koyarsanız, şöyle bir şey yapabilirsiniz:

res = [ /pat1/, /pat2/, ... ]
m   = nil
res.find { |re| m = foo.match(re) }
# Do what you will with `m` now.

Bildirmek mbloğu dışında hala mevcut sonra olmasını sağlar findbloğu ile yapılır ve findbir anahtar size verdiği aynı kısayol uygulayarak davranışı elde edilen kütle gerçek değerini verir en kısa sürede durur. Bu, MatchDataihtiyacınız olduğunda size tamı verir (belki de regexlerinizde adlandırılmış yakalama grupları kullanmak istiyorsanız) ve normal ifadelerinizi arama mantığınızdan güzel bir şekilde ayırır (daha net kod verebilir veya vermeyebilir), hatta normal ifadelerinizi bir yapılandırma dosyasını seçin veya çalışma zamanında istediğiniz kümesini seçin.


Bu caseyaklaşımı kullanarak iplik güvenliğini de düşünüyordum . Belki mu'nun yaklaşımını vaka yaklaşımı (?)
Casper
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.