Dize olarak verilen ifadeyi değerlendirme


283

R, eval()örneğin bir dize tarafından sağlanan hesaplamaları gerçekleştirmek için işlevini kullanıp kullanamayacağını merak ediyorum .

Bu yaygın bir durumdur:

eval("5+5")

Ancak, 10 yerine:

[1] "5+5"

Herhangi bir çözüm?


6
Ayrıştırma ile nasıl çözüleceğini gösteren tüm cevaplara rağmen ... Dil tiplerini neden bir karakterde saklamanız gerekiyor string? Martin Mächler'in cevabı çok daha fazla oyu hak etmeli.
Petr Matousu

7
Teşekkürler @PetrMatousu. Evet, yanlış bilginin şimdi SO'ya nasıl yayıldığını görmek için şok oldum .. eval(parse(text = *)) sahte çözümler geliştiren insanlar tarafından .
Martin Mächler

2
Formun komut dosyalarını çalıştırmak istiyorum: QQ = c('11','12','13','21','22','23')yani: QQ = c (..., 'ij', ..) ile i, j çalıştırmak için değişebilir bir aralıkta değişen. Bu ve benzeri örnekler için, komut dosyasını olarak yazabilirim paste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep="")ve seçenek eval(parse(text=...)), komut dosyasına göre çalışma ortamında vektör QQ'yu oluşturur. "Text = ..." ile olmasaydı bunu yapmanın uygun R kodlayıcı yolu ne olurdu?
VictorZurkowski

Yanıtlar:


418

eval()Fonksiyonu bir ifade olarak değerlendirilir, ancak "5+5"bir dize değil, bir ifadesidir. Dizeyi bir ifadeye dönüştürmek için parse()ile kullanın text=<string>:

> eval(parse(text="5+5"))
[1] 10
> class("5+5")
[1] "character"
> class(parse(text="5+5"))
[1] "expression"

Arayan eval()Birçok davranışları çağırır, bazıları hemen açık değildir:

> class(eval(parse(text="5+5")))
[1] "numeric"
> class(eval(parse(text="gray")))
[1] "function"
> class(eval(parse(text="blue")))
Error in eval(expr, envir, enclos) : object 'blue' not found

Ayrıca bakınız tryCatch .


27
Shane'in aşağıda belirttiği gibi, "
Girdinin

1
eval (ayrıştırma) kullanmanın yan etkileri belirtilmelidir. Örneğin, önceden tanımlanmış bir değişken adınız "David" e eşitse ve eval (ayrıştırma (text = "name") == "Alexander" kullanarak yeniden atarsanız, eval & parse bir döndürmediği için bir hata alırsınız. Değerlendirilebilecek R ifadesi
Crt

1
@NelsonGon: unevaluated ifadeler kullanarak inşa quote(), bquote()ya tarafından sağlanan daha sofistike araçlar rlangpaketinin.
Artem Sokolov

@ArtemSokolov Teşekkürler, bir şekilde bir alternatif arayan bu soruya geri dönmeye devam ediyorum. Ben baktım rlangama bulduğum en yakın hangi sırayla kullanarak ve burada yapılan aynı şey gibi görünüyor hangi kaydırma aynı parse_exprarama oldu . Avantajın ne olacağından emin değilim . parse_exprsparseevalrlang
NelsonGon

1
@NelsonGon: ile rlang, dizelerle değil, ifadelerle doğrudan çalışırsınız. Ayrıştırma adımı gerekmez. İki avantajı vardır. 1. İfade manipülasyonları her zaman geçerli ifadeler üretecektir. Dize manipülasyonları yalnızca geçerli dizeler üretir. Siz bunları ayrıştırıncaya kadar geçerli ifade olup olmadıklarını bilemezsiniz. 2. substitute()Dize dünyasında, işlev çağrılarını değiştirme yeteneğinizi ciddi şekilde sınırlayan işlev sınıfıyla eşdeğer değildir . Bu glm ambalajını düşünün . Bir dize eşdeğeri nasıl görünür?
Artem Sokolov

100

parse()İşlevi karakterleri ifadeye dönüştürmek için kullanabilirsiniz . Ayrıştırma varsayılan olarak bir dosya beklediğinden, girişin metin olduğunu belirtmeniz gerekir:

eval(parse(text="5+5"))

7
> fortunes :: fortune ("answer parse") Eğer cevap parse () ise, genellikle soruyu yeniden düşünmelisiniz. - Thomas Lumley R-help (Şubat 2005)>
Martin Mächler

13
@ MartinMächler Bu ironik, çünkü çekirdek R paketleri parseher zaman kullanıyor! github.com/wch/r-source/…
geneorama

49

Üzgünüm ama neden çok fazla insanın bir ipin değerlendirilebilecek bir şey olduğunu düşündüğünü anlamıyorum. Gerçekten de zihniyetinizi değiştirmelisiniz. Bir taraftaki dizeler ile diğer taraftaki ifadeler, çağrılar, değerlendirme arasındaki tüm bağlantıları unutun.

(Muhtemelen) sadece bağlantı gerçekleşir parse(text = ....)ve tüm iyi R programcıları, bunun ifadeleri (veya çağrıları) oluşturmak için nadiren etkili veya güvenli bir araç olduğunu bilmelidir. Aksine daha öğrenmek substitute(), quote()ve muhtemelen kullanarak gücünü do.call(substitute, ......).

fortunes::fortune("answer is parse")
# If the answer is parse() you should usually rethink the question.
#    -- Thomas Lumley
#       R-help (February 2005)

Aralık.2017: Tamam, işte bir örnek (yorumlarda güzel bir biçimlendirme yok):

q5 <- quote(5+5)
str(q5)
# language 5 + 5

e5 <- expression(5+5)
str(e5)
# expression(5 + 5)

Daha öğreneceksiniz deneyimli olsun eğer o q5bir olduğunu "call", oysa e5bir olduğunu "expression"bile ve e5[[1]]aynıdır q5:

identical(q5, e5[[1]])
# [1] TRUE

4
bir örnek verebilir misiniz? belki bize bir r nesnesinde nasıl 5 + 5 tutacağımızı, daha sonra bir karakter ve eval yerine (parse (text =) yerine alıntı ve ikame kullanarak nasıl değerlendirileceğini)
gösterebilirsin

3
Biraz kaybolabilirim. Hangi noktada 10 kazanıyorsunuz? Yoksa mesele bu değil mi?
Nick S

@RichardDiSalvo: evet, q5 <- quote(5+5)yukarıda olduğu ifade (aslında "çağrı") 5+5ve bir R nesne değil, bir dizedir. İstediğiniz zaman değerlendirebilirsiniz. Tekrarlamak gerekirse, quote,) (), substitute (), ... kullanmak, parse çağrıları ve ifadeleri parse (text =.) İle doğrudan ve daha etkili bir şekilde oluşturur. Kullanmak eval()iyidir, kullanmak parse(text=*)hata eğilimli ve bazen inşaat çağrıları ve onları manipüle karşılaştırıldığında oldukça verimsiz .. @Nick S: Bu eval(q5) ya da eval(e5) çalışan örneğimizde
Martin Mächler

@NickS: 10 almak için çağrıyı / ifadeyi, yani çağrıyı değerlendirirsiniz eval(.). Demek istediğim, insanların daha sonra yapılacak olan çağrıyı inşa etmek için parse(text=.)değil daha çok kullanmaları gerektiğiydi . quote(.)eval()
Martin Mächler

2
eval(quote())birkaç durumda çalışır ancak iyi çalışacağı bazı durumlarda başarısız olur eval(parse()).
NelsonGon

18

Alternatif olarak, kullanabileceğiniz evalsbenim gelen panderyakalama çıktı ve tüm uyarıları, hata ve ham sonuçların yanı sıra diğer iletilere paketin:

> pander::evals("5+5")
[[1]]
$src
[1] "5 + 5"

$result
[1] 10

$output
[1] "[1] 10"

$type
[1] "numeric"

$msg
$msg$messages
NULL

$msg$warnings
NULL

$msg$errors
NULL


$stdout
NULL

attr(,"class")
[1] "evals"

2
Güzel fonksiyon; evaluate::evaluatesonuç nesnesini gerçekten döndürerek kalan bir deliği doldurur ; bu da işlevinizi mclapply ile arama için uygun hale getirir. Umarım bu özellik kalır!
russellpierce

Teşekkürler @rpierce. Bu fonksiyon ilk olarak 2011 yılında rapportpaketimizin bir parçası olarak yazılmıştır ve o zamandan beri aktif olarak korunmaktadır ve o zamandan beri rapporter.net hizmetimizde birkaç başka projenin yanı sıra yoğun bir şekilde kullanılmaktadır - bu yüzden eminim Iken :) yararlı buluyorum sevindim, nazik geribildirim için teşekkürler.
daroczig


2

Benzer şekilde rlang:

eval(parse_expr("5+5"))

3
Buraya bir rlangcevap mı arıyorsunuz, ama bunun temel alternatiflere göre avantajı varsa ne olacak? Aslında, kullanılan kodun yakından incelenmesi, aslında kullanmaktan eval(parse(....))kaçınmak istediğimi gösteriyor.
NelsonGon

4
Sadece bu negatifler değil, adı da yanıltıcı. Bir ifadeyi DEĞERLENDİRMEZ. Kullanıcının karakter argümanları için tasarlandığını bildiğini belirtmek için parse_to_expr ot olarak adlandırılmalıdır.
IRTFM
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.