एक स्ट्रिंग के रूप में दी गई अभिव्यक्ति का मूल्यांकन करें


283

मैं यह जानने के लिए उत्सुक हूं कि क्या आर eval()एक स्ट्रिंग द्वारा प्रदान की गई गणना करने के लिए अपने फ़ंक्शन का उपयोग कर सकता है ।

यह एक सामान्य मामला है:

eval("5+5")

हालांकि, 10 के बजाय मुझे मिलता है:

[1] "5+5"

कोई भी समाधान?


6
सभी उत्तरों के बावजूद कि पार्स के साथ इसे कैसे हल किया जाए ... आपको एक चरित्र में भाषा प्रकारों को संग्रहीत करने की आवश्यकता क्यों है string? मार्टिन मेक्लेर के जवाब को और अधिक बढ़ावा देना चाहिए।
पेट्र मटोसू

7
साभार @PetrMatousu हां, मैं यह देखकर हैरान हूं कि अब एसओ पर गलत सूचना कैसे फैली हुई है। लोग eval(parse(text = *)) नकली समाधान निकाल रहे हैं।
मार्टिन मॉचलर

2
मैं फॉर्म के स्क्रिप्स को चलाना चाहता हूं: QQ = c('11','12','13','21','22','23')यानी: QQ = c (..., 'ij', ..) i के साथ, j एक सीमा पर अलग-अलग है जो कि रन-टू-रन से भिन्न हो सकते हैं। इस और इसी तरह के उदाहरणों के लिए, मैं स्क्रिप्ट को इस प्रकार लिख सकता हूं paste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep=""), और विकल्प eval(parse(text=...))स्क्रिप्ट के अनुसार काम के माहौल में वेक्टर QQ बनाता है। ऐसा करने के लिए उचित आर कोडर तरीका क्या होगा, यदि "टेक्स्ट = ..." के साथ नहीं है?
विक्टरज़ुरोव्स्की

जवाबों:


418

eval()समारोह एक अभिव्यक्ति का मूल्यांकन करता है, लेकिन "5+5"एक स्ट्रिंग, नहीं एक अभिव्यक्ति है। का प्रयोग करें parse()साथ text=<string>एक अभिव्यक्ति में स्ट्रिंग को बदलने के लिए:

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

कॉलिंग eval()कई व्यवहारों को आमंत्रित करती है, कुछ तुरंत स्पष्ट नहीं हैं:

> 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

यह भी देखें tryCatch


27
जैसा कि शेन नीचे लिखते हैं, "आपको यह निर्दिष्ट करने की आवश्यकता है कि इनपुट पाठ है, क्योंकि पार्स डिफ़ॉल्ट रूप से एक फ़ाइल की उम्मीद करता है"
पैट्रिकटी

1
eval (पार्स) का उपयोग करने के दुष्प्रभाव को निर्दिष्ट किया जाना चाहिए। उदाहरण के लिए, यदि आपके पास "डेविड" के बराबर एक पूर्व-परिभाषित चर नाम है और आप eval (पार्स (पाठ = "नाम") == "अलेक्जेंडर" का उपयोग करके पुन: असाइन करते हैं, तो आपको त्रुटि मिलेगी क्योंकि eval और parse वापस नहीं आते हैं अभिव्यक्ति है कि मूल्यांकन किया जा सकता है।
Crt

1
@NelsonGon: unevaluated भाव का प्रयोग कर बनाया quote(), bquote()या और अधिक परिष्कृत द्वारा प्रदान की उपकरण rlangपैकेज।
आर्टेम सोकोलोव

@ArtemSokolov धन्यवाद, मैं किसी भी तरह एक विकल्प की तलाश में इस सवाल पर वापस आ रहा हूँ। मैंने देखा है, rlangलेकिन मुझे सबसे करीब से पता चला कि parse_exprकौन सी कॉल थी जो parse_exprsबदले में parseइसे इस्तेमाल करने और लपेटने के समान है evalजिसमें ऐसा ही लगता है जैसा कि यहां किया गया है। मैं अनिश्चित हूं कि फायदा क्या होगा rlang
नेल्सनगॉन

1
@ नेल्सन: साथ rlang, आप सीधे भावों के साथ काम करेंगे, तार नहीं। कोई पार्स कदम आवश्यक नहीं है। इसके दो फायदे हैं। 1. अभिव्यक्ति में हेरफेर हमेशा मान्य अभिव्यक्ति पैदा करेगा। स्ट्रिंग जोड़तोड़ केवल वैध स्ट्रिंग्स का उत्पादन करेगा। आपको पता नहीं चलेगा कि क्या वे वैध अभिव्यक्ति हैं जब तक आप उन्हें पार्स नहीं करते। 2. substitute()स्ट्रिंग दुनिया में फ़ंक्शन के वर्ग के बराबर नहीं है, जो फ़ंक्शन कॉल में हेरफेर करने की आपकी क्षमता को गंभीर रूप से सीमित करता है। इस glm आवरण पर विचार करें । एक स्ट्रिंग समकक्ष कैसा दिखेगा?
आर्टेम सोकोलोव

100

आप parse()वर्णों को अभिव्यक्ति में बदलने के लिए फ़ंक्शन का उपयोग कर सकते हैं । आपको यह निर्दिष्ट करने की आवश्यकता है कि इनपुट पाठ है, क्योंकि पार्स डिफ़ॉल्ट रूप से एक फ़ाइल की उम्मीद करता है:

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

7
> भाग्य :: भाग्य ("उत्तर पार्स है") यदि उत्तर पार्स है () तो आपको आमतौर पर प्रश्न पर पुनर्विचार करना चाहिए। - थॉमस लुमले आर-हेल्प (फरवरी 2005)>
मार्टिन मचलर

13
@ मार्टिनमैक्लर यह विडंबना है, क्योंकि कोर आर संकुल parseहर समय उपयोग करते हैं! github.com/wch/r-source/…
जिनोरमा

49

क्षमा करें, लेकिन मुझे यह समझ में नहीं आता है कि बहुत से लोग यह भी सोचते हैं कि स्ट्रिंग एक ऐसी चीज थी जिसका मूल्यांकन किया जा सकता था। आपको अपनी मानसिकता बदलनी चाहिए, वास्तव में। एक तरफ स्ट्रिंग्स और दूसरी तरफ एक्सप्रेशन, कॉल, मूल्यांकन के बीच सभी कनेक्शनों को भूल जाएं।

(संभवतः) केवल कनेक्शन के माध्यम से है parse(text = ....)और सभी अच्छे आर प्रोग्रामर को पता होना चाहिए कि यह अभिव्यक्ति (या कॉल) के निर्माण के लिए शायद ही कभी एक कुशल या सुरक्षित साधन है। बल्कि अधिक के बारे में जानने substitute(), quote()है, और संभवतः का उपयोग कर की शक्ति 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)

Dec.2017: ठीक है, यहां एक उदाहरण है (टिप्पणियों में, कोई अच्छा स्वरूपण नहीं है):

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

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

और यदि आप और अधिक अनुभवी हो आप यह जान सकेंगे कि q5एक है "call"जबकि e5एक है "expression"कि, और यहां तक कि e5[[1]]के समान है q5:

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

4
क्या आप एक उदाहरण दे सकते हैं? हो सकता है कि आप हमें एक आर ऑब्जेक्ट में "होल्ड ऑन" 5 से 5 + दिखा सकते हैं, फिर बाद में इसका मूल्यांकन करें, एक चरित्र और
इवल

3
मैं थोड़ा खो सकता हूं। आप किस बिंदु पर 10 प्राप्त करते हैं? या कि बात नहीं है?
निक एस

@RichardDiSalvo: हाँ, q5 <- quote(5+5)इसके बाद के संस्करण है अभिव्यक्ति (वास्तव में "कॉल") 5+5और यह एक अनुसंधान वस्तु, लेकिन नहीं एक श्रृंखला है। आप किसी भी समय इसका मूल्यांकन कर सकते हैं। पुन:: का उपयोग करते हुए, उद्धरण (), स्थानापन्न (), ... इसके बजाय पार्स कॉल या अभिव्यक्ति को सीधे और अधिक कुशलता से बनाता है (पाठ =।)। का उपयोग करना eval()ठीक है, parse(text=*)त्रुटि का उपयोग करना और निर्माण कॉल की तुलना में कभी-कभी काफी अक्षम है और उन्हें जोड़ तोड़ कर रहा है .. @ निक एस: यह eval(q5) या eval(e5) हमारे चल रहे उदाहरण में है
मार्टिन मॉचलर

@ निकस: 10 प्राप्त करने के लिए, आप कॉल / एक्सप्रेशन का मूल्यांकन करते हैं, अर्थात, eval(.)उस पर कॉल करें । मेरा कहना था कि लोगों को कॉल का निर्माण करने के लिए उपयोग नहीं करना चाहिए , parse(text=.)बल्कि quote(.)बाद में eval()एड करना चाहिए ।
मार्टिन मचलर

2
eval(quote())कुछ मामलों में काम करता है, लेकिन कुछ मामलों में विफल हो जाता है जहां eval(parse())अच्छा काम करेगा।
नेल्सनगॉन

18

वैकल्पिक रूप से, आप evalsमेरे panderपैकेज से कच्चे माल के साथ आउटपुट और सभी चेतावनियों, त्रुटियों और अन्य संदेशों को पकड़ने के लिए उपयोग कर सकते हैं :

> 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
अच्छा कार्य; evaluate::evaluateवास्तव में परिणाम वस्तु वापस करके एक छेद छोड़ दिया जाता है; जो आपके कार्य को mclapply के माध्यम से कॉल करने के लिए उपयुक्त छोड़ देता है। मुझे आशा है कि सुविधा बनी हुई है!
रसैलपिएर्स

साभार, @rpierce यह फ़ंक्शन मूल रूप से 2011 में हमारे rapportपैकेज के हिस्से के रूप में लिखा गया था , और तब से सक्रिय रूप से बनाए रखा गया है, क्योंकि हमारे rapporter.net सेवा में भारी उपयोग किया जा रहा है इसके अलावा कुछ अन्य परियोजनाओं के साथ भी - इसलिए मुझे यकीन है कि यह एक के लिए बनाए रखा जाएगा। जबकि :) मुझे खुशी है कि आप इसे उपयोगी पाते हैं, अपनी तरह की प्रतिक्रिया के लिए धन्यवाद।
daroczig


2

इसी तरह का उपयोग कर rlang:

eval(parse_expr("5+5"))

3
यहाँ एक rlangउत्तर की तलाश में आया था लेकिन क्या होगा यदि कोई इस आधार विकल्प का लाभ उठाता है? दरअसल, उपयोग किए गए कोड की करीबी परीक्षा से पता चलता है कि यह वास्तव में उपयोग eval(parse(....))करना है जिससे मैं बचना चाहता था।
नेल्सनगॉन

4
न केवल उन नकारात्मक, बल्कि इसका नाम भी भ्रामक है। यह एक अभिव्यक्ति का मूल्यांकन नहीं कर रहा है। संकेत करने के लिए parse_to_expr ot को कुछ और कहा जाना चाहिए ताकि उपयोगकर्ता को पता चले कि यह चरित्र तर्क के लिए है।
IRTFM
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.