संकेतन अभिव्यक्तियों को उपसर्ग संकेतन में बदलें


23

जब मैंने इस बंद प्रश्न का शीर्षक देखा , तो मुझे लगा कि यह एक दिलचस्प कोड गोल्फ चुनौती है। तो मुझे इसे इस तरह प्रस्तुत करें:

चुनौती:

एक प्रोग्राम, एक्सप्रेशन या सबरूटीन लिखें, जो कि इनफिक्स नोटेशन में एक अंकगणितीय अभिव्यक्ति देता है , जैसे 1 + 2, पोस्टफिक्स नोटेशन में एक ही अभिव्यक्ति को आउटपुट करता है , अर्थात 1 2 +

(नोट: इसी तरह की चुनौती पहले जनवरी में पोस्ट की गई थी। हालांकि, मुझे लगता है कि इस अलग चुनौती को सही ठहराने के लिए दो कार्य पर्याप्त रूप से अलग-अलग हैं। इसके अलावा, मैंने केवल नीचे सब कुछ टाइप करने के बाद दूसरे सूत्र पर ध्यान दिया है, और मैं बल्कि करूँगा। बस इसे दूर नहीं फेंक दो।)

इनपुट:

इनपुट से मिलकर एक वैध इन्फ़िक्स अंकगणितीय अभिव्यक्ति के होते संख्या (गैर नकारात्मक पूर्णांक एक या अधिक दशमलव अंक के दृश्यों के रूप में प्रतिनिधित्व), संतुलित कोष्ठकों एक समूहीकृत उपसूचक इंगित करने के लिए, और चार इन्फ़िक्स द्विआधारी ऑपरेटरों + , -, *और /। अंतरिक्ष वर्णों की एक अनियंत्रित संख्या द्वारा इनमें से किसी को अलग किया जा सकता है (और संपूर्ण अभिव्यक्ति को घेर लिया गया है), जिसे अनदेखा किया जाना चाहिए। 1

औपचारिक व्याकरण पसंद करने वालों के लिए, यहाँ एक साधारण बीएनएफ-जैसा व्याकरण है जो वैध इनपुट को परिभाषित करता है। संक्षिप्तता और स्पष्टता के लिए, व्याकरण में वैकल्पिक स्थान शामिल नहीं हैं, जो कि किसी भी दो टोकन (संख्या के भीतर अंकों के अलावा) के बीच हो सकते हैं:

expression     := number | subexpression | expression operator expression
subexpression  := "(" expression ")"
operator       := "+" | "-" | "*" | "/"
number         := digit | digit number
digit          := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

1 एकमात्र मामला जहां रिक्त स्थान की उपस्थिति पार्सिंग को प्रभावित कर सकती है, जब वे दो लगातार संख्याओं को अलग करते हैं; हालाँकि, चूंकि ऑपरेटर द्वारा अलग किए गए दो नंबर एक वैध इनफ़िक्स एक्सप्रेशन में नहीं हो सकते, इसलिए यह मामला वैध इनपुट में कभी नहीं हो सकता है।

आउटपुट:

आउटपुट इनपुट के बराबर एक पोस्टफिक्स एक्सप्रेशन होना चाहिए। उत्पादन अभिव्यक्ति, साथ ही नंबर और ऑपरेटरों से मिलकर चाहिए एक भी अंतरिक्ष चरित्र आसन्न टोकन के प्रत्येक जोड़ी के बीच, निम्नलिखित व्याकरण (जो के रूप में करता है रिक्त स्थान शामिल हैं) 2 :

expression  := number | expression sp expression sp operator
operator    := "+" | "-" | "*" | "/"
number      := digit | digit number
digit       := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
sp          := " "

2 सादगी के लिए फिर से, numberइस व्याकरण में उत्पादन प्रमुख शून्य के साथ संख्याओं को स्वीकार करता है, भले ही वे नीचे के नियमों द्वारा आउटपुट में निषिद्ध हैं।

संचालक वरीयता:

कोष्ठक की अनुपस्थिति में, निम्नलिखित पूर्ववर्ती नियम लागू होते हैं:

  • ऑपरेटरों *और की /तुलना में उच्च वरीयता है +और -
  • ऑपरेटरों *और /एक दूसरे के लिए समान मिसाल है।
  • ऑपरेटरों +और -एक दूसरे के लिए समान मिसाल है।
  • सभी ऑपरेटर बाएं सहयोगी हैं।

उदाहरण के लिए, निम्नलिखित दो भाव समतुल्य हैं:

1 + 2 / 3 * 4 - 5 + 6 * 7
((1 + ((2 / 3) * 4)) - 5) + (6 * 7)

और उन्हें निम्नलिखित उत्पादन प्राप्त करना चाहिए:

1 2 3 / 4 * + 5 - 6 7 * +

(ये सी भाषा के रूप में और सबसे से व्युत्पन्न भाषाओं में एक ही पूर्वता नियम हैं। वे शायद, नियमों आप प्राथमिक स्कूल में सिखाया जाता था जैसे लगते हैं के रिश्तेदार पूर्वता के लिए संभवतः सिवाय *और /।)

विविध नियम:

  • यदि दिया गया समाधान एक अभिव्यक्ति या सबरूटिन है, तो इनपुट की आपूर्ति की जानी चाहिए और आउटपुट एक स्ट्रिंग के रूप में वापस आ जाता है। यदि समाधान एक पूर्ण कार्यक्रम है, तो इसे मानक इनपुट से इनफ़िक्स एक्सप्रेशन वाली एक पंक्ति को पढ़ना चाहिए और मानक आउटपुट के लिए पोस्टफ़िक्स संस्करण वाले लाइन को प्रिंट करना चाहिए।

  • इनपुट में संख्याओं में अग्रणी शून्य शामिल हो सकते हैं। आउटपुट में संख्याओं में अग्रणी शून्य नहीं होना चाहिए (संख्या 0 को छोड़कर, जो आउटपुट के रूप में होगा 0)।

  • आपसे किसी भी तरह से अभिव्यक्ति का मूल्यांकन या अनुकूलन करने की उम्मीद नहीं की जाती है। विशेष रूप से, आपको यह नहीं समझना चाहिए कि ऑपरेटर आवश्यक रूप से किसी भी साहचर्य, कम्यूटेटिव या अन्य बीजीय पहचान को संतुष्ट करते हैं। यही है, आपको यह नहीं मान लेना चाहिए कि उदाहरण 1 + 2बराबर है 2 + 1या कि 1 + (2 + 3)बराबर है (1 + 2) + 3

  • आप मान सकते हैं कि इनपुट में संख्या 2 31 - 1 = 2147483647 से अधिक नहीं है ।

इन नियमों का उद्देश्य यह सुनिश्चित करना है कि इनपुट द्वारा सही आउटपुट विशिष्ट रूप से परिभाषित किया गया है।

उदाहरण:

यहाँ कुछ मान्य इनपुट अभिव्यक्तियाँ और संबंधित आउटपुट दिए गए हैं "input" -> "output":

"1"                  ->  "1"
"1 + 2"              ->  "1 2 +"
" 001  +  02 "       ->  "1 2 +"
"(((((1))) + (2)))"  ->  "1 2 +"
"1+2"                ->  "1 2 +"
"1 + 2 + 3"          ->  "1 2 + 3 +"
"1 + (2 + 3)"        ->  "1 2 3 + +"
"1 + 2 * 3"          ->  "1 2 3 * +"
"1 / 2 * 3"          ->  "1 2 / 3 *"
"0102 + 0000"        ->  "102 0 +"
"0-1+(2-3)*4-5*(6-(7+8)/9+10)" -> "0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -"

(कम से कम, मुझे आशा है कि ये सभी सही हैं; मैंने हाथ से रूपांतरण किया था, इसलिए गलतियों में कमी हो सकती है।)

बस स्पष्ट होने के लिए, निम्नलिखित इनपुट सभी अमान्य हैं; इससे कोई फर्क नहीं पड़ता है कि अगर आपका समाधान उन्हें दिया जाता है, तो (हालांकि, उदाहरण के लिए, त्रुटि संदेश लौटा देना, किसी स्मृति की अनंत राशि की तुलना में अच्छा है)

""
"x"
"1 2"
"1 + + 2"
"-1"
"3.141592653589793"
"10,000,000,001"
"(1 + 2"
"(1 + 2)) * (3 / (4)"

क्या लिस्प की तरह संकेतन स्वीकार्य है? उदाहरण के लिए 1 2 3 4 +`1 + 2 + 3 + 4`।
होलेथ

3
@ हौलेथ: इस चुनौती में नहीं, नहीं। इसके अलावा, कोष्ठक के बिना, आप कैसे पार्स करेंगे 1 2 3 4 + *?
इल्मरी करोनें

तो, otuput में कोई अनुगामी व्हाट्सएप (एक नई रेखा सहित) की अनुमति नहीं है?
ब्रेडबॉक्स

@breadbox: अनुगामी newlines ठीक हैं। वास्तव में, मुझे स्पष्ट रूप से स्पष्ट करना चाहिए कि किसी भी अनुगामी व्हाट्सएप की अनुमति है।
इल्मरी करोनें

मेरे पास एक समाधान है जो अंतिम वैध उदाहरण के लिए "0 1 - 2 3 - 4 * 5 6 7 8 + 9 / - 10 + * - +" आउटपुट करता है, जो मुझे सही लगता है। क्या आप जांच सकते हैं? (अंतिम + संचालक को नोटिस करें)
coredump

जवाबों:


8

शेल बर्तन - 60 वर्ण

bc -c|sed -re's/[@iK:Wr]+/ /g;s/[^0-9]/ &/g;s/ +/ /g;s/^ //'

विभिन्न समस्याओं को ठीक किया, लेकिन यह बहुत लंबा हो गया :(


1
यह बल्कि चालाक है, सिवाय इसके कि यह संख्याओं को 9 से अधिक सही ढंग से संभालने के लिए प्रतीत नहीं होता है।
ब्रेडबॉक्स

@breadbox, sed -re's/[:@iKWr]+/ /g'इसे 1 वर्ण लागत पर ठीक करता है।
बदसूरत

उफ़, हालांकि @ugoren सुझाव काम नहीं करता है क्योंकि लगातार ऑपरेटर अब उनके बीच जगह नहीं रखते हैं; मैं उस के लिए भी एक तय करने के साथ आया हूँ
Geoff Reedy

4

सी, 250 245 236 193 185 चर

char*p,b[99];f(char*s){int t=0;for(;*p-32?
*p>47?printf("%d ",strtol(p,&p,10)):*p==40?f(p++),++p:
t&&s[t]%5==2|*p%5-2?printf("%c ",s[t--]):*p>41?s[++t]=*p++:0:++p;);}
main(){f(p=gets(b));}

यहाँ ungolfed स्रोत का पठनीय संस्करण है, जो अभी भी मूल तर्क को दर्शाता है। यह वास्तव में एक सीधा कार्यक्रम है। एकमात्र वास्तविक काम जो करना है, वह एक उच्च-संघातिकी संचालक का सामना करने पर एक कम-एसोसिएटिविटी ऑपरेटर को एक स्टैक पर धकेलना है, और फिर इसे उस सब-डेफ़िसिट के "अंत" पर वापस पॉप करना है।

#include <stdio.h>
#include <stdlib.h>

static char buf[256], stack[256];
static char *p = buf;

static char *fix(char *ops)
{
    int sp = 0;

    for ( ; *p && *p != '\n' && *p != ')' ; ++p) {
        if (*p == ' ') {
            continue;
        } else if (*p >= '0') {
            printf("%ld ", strtol(p, &p, 10));
            --p;
        } else if (*p == '(') {
            ++p;
            fix(ops + sp);
        } else {
            while (sp) {
                if ((ops[sp] == '+' || ops[sp] == '-') &&
                        (*p == '*' || *p == '/')) {
                    break;
                } else {
                    printf("%c ", ops[sp--]);
                }
            }
            ops[++sp] = *p;
        }
    }
    while (sp)
        printf("%c ", ops[sp--]);
    return p;
}

int main(void)
{
    fgets(buf, sizeof buf, stdin);
    fix(stack);
    return 0;
}

हटाकर वर्ण बचाएं if। जैसे if(!*p||*p==41)return p;s[++t]=*p;}->return*p&&*p-41?s[++t]=*p:p;
बदसूरत

K & R शैली की घोषणा:*f(p,s)char*p,s;{
बदसूरत

1. यदि ifपरीक्षा में विफल रहता है तो इसे वापस करने के लिए एक त्रुटि है । 2. मुझे पता है, लेकिन K & R फंक्शन डिकल्स वह जगह है जहां मैं रेखा खींचता हूं। मैं अभी उनके पास नहीं जा सकता।
ब्रेडबॉक्स

मैंने सोचा कि वापसी वैसे भी समारोह के अंत में है। याद किया }}और for। लेकिन यहाँ एक विद्रोह है:printf(" %ld"+!a,...
बदसूरत

1
इसके अलावा, मुझे लगता है कि आपको pवैश्विक बनाना चाहिए (पुनरावर्ती कॉल सिर्फ कॉल pकरने वाले को वापस असाइन करता है )। फिर करते हैं f(p=gets(b))
प्रात

2

बैश w / हास्केल w / C प्रीप्रोसेसर सेड, 180 195 198 275

echo 'CNumO+O-O*fromInteger=show
CFractionalO/
main=putStr$'$*|sed 's/C\([^O]*\)/instance \1 String where /g
s/O\(.\?\)/a\1b=unwords\[a,b,\"\1\"];/g'|runghc -XFlexibleInstances 2>w

अंत में, यह अब सी समाधान से अधिक नहीं है। महत्वपूर्ण हास्केल भाग लगभग ई.पू. समाधान की तरह ही आलसी है ...

कमांड-लाइन मापदंडों के रूप में इनपुट लेता है। wयदि आपको यह परिवर्तन पसंद नहीं है, तो कुछ ghc चेतावनी संदेशों के साथ एक फ़ाइल बनाई जाएगी runghc 2>/dev/null


1
Basked? ( बेस एच + एच एसे पूछेंगे + एस एड )
कैलकुलेटरफलाइन

2

पायथन 2, 290 272 268 250 243 238 बाइट्स

अब आखिरकार JS जवाब से कम!

यह एक पूर्ण कार्यक्रम है जो शंटिंग यार्ड एल्गोरिदम के एक बुनियादी कार्यान्वयन का उपयोग करता है । इनपुट एक उद्धृत स्ट्रिंग के रूप में दिया गया है, और परिणाम के लिए मुद्रित किया गया है STDOUT

import re
O=[];B=[]
for t in re.findall('\d+|\S',input()):exec("O=[t]+O","i=O.index('(');B+=O[:i];O=O[i+1:]","while O and'('<O[0]and(t in'*/')<=(O[0]in'*/'):B+=O.pop(0)\nO=[t]+O","B+=`int(t)`,")[(t>'/')+(t>')')+(t>'(')]
print' '.join(B+O)

इसे ऑनलाइन आज़माएं!


स्पष्टीकरण:

पहली चीज जो हमें करने की ज़रूरत है वह इनपुट को टोकन में बदलना है। हम इसका उपयोग रेगेक्स के सभी मैचों को खोजने के लिए करते हैं \d+|\S, जिसका मोटे तौर पर "अंकों के किसी भी समूह, और किसी भी गैर-अंतरिक्ष चरित्र" में अनुवाद किया जाता है। यह व्हाट्सएप को हटाता है, आसन्न अंकों को एकल टोकन के रूप में, और पार्स ऑपरेटरों को अलग से निकालता है।

शंटिंग यार्ड एल्गोरिथ्म के लिए, 4 अलग-अलग टोकन प्रकार हैं जिन्हें हमें संभालने की आवश्यकता है:

  • ( - बाएं कोष्ठक
  • ) - सही कोष्ठक
  • +-*/ - संचालक
  • 9876543210 - संख्यात्मक शाब्दिक

शुक्र है, इनमें से ASCII कोड दिखाए गए क्रम में समूहीकृत हैं, इसलिए हम (t>'/')+(t>')')+(t>'(')टोकन प्रकार की गणना करने के लिए अभिव्यक्ति का उपयोग कर सकते हैं । इसका परिणाम 3 अंकों के लिए, 2 ऑपरेटरों के लिए, 1 सही कोष्ठक के लिए और 0 एक बाएं कोष्ठक के लिए होता है।

इन मूल्यों का उपयोग करते हुए, हम execटोकन प्रकार के आधार पर निष्पादित करने के लिए इसी स्निपेट को प्राप्त करने के बाद बड़े ट्यूपल में अनुक्रमित करते हैं । यह प्रत्येक टोकन के लिए अलग है और शंटिंग यार्ड एल्गोरिथ्म की रीढ़ है। दो सूचियों का उपयोग किया जाता है (स्टैक के रूप में): O(ऑपरेशन स्टैक) और B(आउटपुट बफर)। सभी टोकन चलाए जाने के बाद, Oस्टैक पर शेष ऑपरेटरों को आउटपुट बफर के साथ समाहित किया जाता है, और परिणाम मुद्रित किया जाता है।


2

प्रोलॉग (एसडब्ल्यूआई-प्रोलॉग) , 113 बाइट्स

c(Z,Q):-Z=..[A,B,C],c(B,S),c(C,T),concat_atom([S,T,A],' ',Q);term_to_atom(Z,Q).
p(X,Q):-term_to_atom(Z,X),c(Z,Q).

इसे ऑनलाइन आज़माएं!

जीएनयू प्रोलॉग की तुलना में एसडब्ल्यूआई प्रोलॉग के पास बिल्डरों का एक बेहतर सेट है, लेकिन यह अभी भी प्रोलॉग के सिंटैक्स की क्रिया द्वारा कुछ हद तक वापस आयोजित किया गया है।

व्याख्या

term_to_atomअगर, पीछे की ओर चला जाता है, तो एक पार्स ट्री में एक infix- संकेतन अभिव्यक्ति (एक परमाणु के रूप में संग्रहीत) को पार्स करें (सामान्य पूर्ववर्ती नियमों का पालन करते हुए, और अग्रणी शून्य और व्हाट्सएप को हटा दें)। तब हम सहायक cपेड़ पर एक संरचनात्मक पुनरावृत्ति करने के लिए सहायक का उपयोग करते हैं , एक गहराई से पहले तरीके से उपसर्ग संकेतन में परिवर्तित होता है।


1

जावास्क्रिप्ट (ईएस 6), 244 बाइट्स

f=(s,o={'+':1,'-':1,'*':2,'/':2},a=[],p='',g=c=>o[l=a.pop()]>=o[c]?g(c,p+=l+' '):a.push(l||'',c))=>(s.match(/[)(+*/-]|\d+/g).map(c=>o[c]?g(c):(c==')'?eval(`for(;(i=a.pop())&&i!='(';)p+=i+' '`):c=='('?a.push(c):p+=+c+' ')),p+a.reverse().join` `)

उदाहरण:
कॉल: f('0-1+(2-3)*4-5*(6-(7+8)/9+10)')
आउटपुट: 0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -(अनुगामी स्थान के साथ)

स्पष्टीकरण:

f=(s,                                                     //Input string
    o={'+':1,'-':1,'*':2,'/':2},                          //Object used to compare precedence between operators
    a=[],                                                 //Array used to stack operators
    p='',                                                 //String used to store the result
    g=c=>                                                 //Function to manage operator stack
        o[l=a.pop()]>=o[c]?                               //  If the last stacked operator has the same or higher precedence
            g(c,p+=l+' '):                                //  Then adds it to the result and call g(c) again
            a.push(l||'',c)                               //  Else restack the last operator and adds the current one, ends the recursion.
)=>                                                       
    (s.match(/[)(+*/-]|\d+/g)                             //Getting all operands and operators
    .map(c=>                                              //for each operands or operators
        o[c]?                                             //If it's an operator defined in the object o
            g(c)                                          //Then manage the stack
            :(c==')'?                                     //Else if it's a closing parenthese
                eval(`                                    //Then
                    for(;(i=a.pop())&&i!='(';)            //  Until it's an opening parenthese
                        p+=i+' '                          //  Adds the last operator to the result
                `)                                        
                :c=='('?                                  //Else if it's an opening parenthese
                    a.push(c)                             //Then push it on the stack
                    :p+=+c+' '                            //Else it's an operand: adds it to the result (+c removes the leading 0s)
        )                                                 
    )                                                     
    ,p+a.reverse().join` `)                               //Adds the last operators on the stack to get the final result

1

आर, 142 बाइट्स

आर खुद को पार्स करने में सक्षम है, इसलिए पहिया को फिर से आविष्कार करने के बजाय, हमने बस पार्सर को काम करने के लिए रखा है, जो उपसर्ग संकेतन को आउटपुट करता है, और इसे पुनरावृत्ति संकेतन पर स्विच करने के लिए एक पुनरावर्ती फ़ंक्शन का उपयोग करता है।

f=function(x,p=1){
if(p)x=match.call()[[2]]
if((l=length(x))>1){
f(x[[2]],0)
if(l>2)f(x[[3]],0)
if((z=x[[1]])!="(")cat(z,"")
}else cat(x,"")
}

pतर्क अमानक मूल्यांकन (आर प्रोग्रामर हर जगह का अभिशाप) के उपयोग को नियंत्रित करने के लिए है, और कुछ अतिरिक्त देखते हैं ifवहाँ में कोष्ठक के outputting (जिसे हम बचना चाहते हैं) को नियंत्रित करने के।

इनपुट: (0-1+(2-3)*4-5*(6-(7+8)/9+10))

आउटपुट: 0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -

इनपुट: (((((1))) + (2)))

आउटपुट: 1 2 +

एक बोनस के रूप में, यह मनमाने प्रतीकों के साथ काम करता है, और दो तर्कों के साथ कोई भी पूर्व-परिभाषित कार्य:

यूलर की पहचान

इनपुट: e^(i*pi)-1

आउटपुट: e i pi * ^ 1 -

1 और 100 के बीच 13 का लाभांश

इनपुट: which(1:100 %% 13 == 0)

आउटपुट: 1 100 : 13 %% 0 == which

समय के एक समारोह के रूप में बच्चे के चिकन वजन का रेखीय प्रतिगमन

इनपुट: summary(lm(weight~Time, data=ChickWeight))

आउटपुट: weight Time ~ ChickWeight lm summary

आखिरी उदाहरण शायद ओपी के दायरे से थोड़ा बाहर है, लेकिन यह पोस्टफिक्स नोटेशन का उपयोग करता है, इसलिए ...

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.