Als ich den Titel dieser geschlossenen Frage sah , fand ich, dass es sich um eine interessante Code-Golf-Herausforderung handelte. Lassen Sie es mich als solches darstellen:
Herausforderung:
Ein Programm schreiben, Expression oder Unterprogramm , das, ein arithmetischer Ausdruck in gegebenem Infix - Schreibweise , wie 1 + 2
gibt den gleichen Ausdruck in Postfix - Schreibweise , dh 1 2 +
.
(Hinweis: Eine ähnliche Herausforderung wurde Anfang Januar veröffentlicht. Ich bin jedoch der Meinung, dass die beiden Aufgaben im Detail ausreichend unterschiedlich sind, um diese separate Herausforderung zu rechtfertigen. Außerdem habe ich den anderen Thread erst bemerkt, nachdem ich alles unten eingegeben habe, und ich würde es vorziehen nicht einfach alles wegwerfen.)
Eingang:
Die Eingabe besteht aus einem gültigen Infix arithmetischen Ausdruck , der aus Zahlen (nicht negative ganzen Zahlen als Sequenzen von einem oder mehreren Dezimalziffern dargestellt) ausgeglichen Klammern einen gruppierte Teilausdruck , um anzuzeigen, und die vier Infix binären Operatoren +
, -
, *
und /
. Jedes dieser Zeichen kann von einer beliebigen Anzahl von Leerzeichen getrennt (und der gesamte Ausdruck von einem Leerzeichen umgeben) werden, die ignoriert werden sollten. 1
Für diejenigen, die formale Grammatiken mögen, ist hier eine einfache BNF-ähnliche Grammatik, die gültige Eingaben definiert. Der Kürze und Klarheit halber enthält die Grammatik keine optionalen Leerzeichen, die zwischen zwei beliebigen Token (außer Ziffern innerhalb einer Zahl) auftreten können:
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 Der einzige Fall, in dem das Vorhandensein von Leerzeichen die Syntaxanalyse beeinflussen kann, besteht darin, dass zwei aufeinanderfolgende Zahlen voneinander getrennt werden. Da jedoch zwei nicht durch einen Operator getrennte Zahlen in einem gültigen Infix-Ausdruck nicht vorkommen können, kann dieser Fall bei einer gültigen Eingabe niemals auftreten.
Ausgabe:
Die Ausgabe sollte ein Postfix-Ausdruck sein, der der Eingabe entspricht. Der Ausgang Ausdruck sollte nur aus Zahlen und Operatoren besteht, mit einem einzigen Leerzeichen zwischen jedem Paar von benachbartem Tokens, wie in der folgenden Grammatik (die nicht die Räume umfasst) 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 Wiederum der Einfachheit halber lässt die number
Produktion in dieser Grammatik Zahlen mit führenden Nullen zu, obwohl sie in der Ausgabe nach den folgenden Regeln verboten sind.
Operator-Rangfolge:
In Abwesenheit von Klammern gelten die folgenden Vorrangregeln:
- Die Operatoren
*
und/
haben eine höhere Priorität als+
und-
. - Die Operatoren
*
und/
haben untereinander den gleichen Vorrang. - Die Operatoren
+
und-
haben untereinander den gleichen Vorrang. - Alle Operatoren sind linksassoziativ.
Die folgenden zwei Ausdrücke sind beispielsweise äquivalent:
1 + 2 / 3 * 4 - 5 + 6 * 7
((1 + ((2 / 3) * 4)) - 5) + (6 * 7)
und sie sollten beide die folgende Ausgabe ergeben:
1 2 3 / 4 * + 5 - 6 7 * +
(Dies sind die gleichen Prioritätsregeln wie in der C-Sprache und in den meisten davon abgeleiteten Sprachen. Sie ähneln wahrscheinlich den Regeln, die Sie in der Grundschule unterrichtet haben, außer möglicherweise der relativen Priorität von *
und /
.)
Verschiedene Regeln:
Wenn die angegebene Lösung ein Ausdruck oder eine Unterroutine ist, sollte die Eingabe geliefert und die Ausgabe als einzelne Zeichenfolge zurückgegeben werden. Wenn die Lösung ein vollständiges Programm ist, sollte sie eine Zeile mit dem Infix-Ausdruck von der Standardeingabe lesen und eine Zeile mit der Postfix-Version in der Standardausgabe ausgeben.
Zahlen in der Eingabe können führende Nullen enthalten. Zahlen in der Ausgabe dürfen keine führenden Nullen haben (mit Ausnahme der Zahl 0, die als ausgegeben werden soll
0
).Es wird nicht erwartet, dass Sie den Ausdruck in irgendeiner Weise bewerten oder optimieren. Insbesondere sollten Sie nicht davon ausgehen, dass die Operatoren notwendigerweise assoziative, kommutative oder andere algebraische Identitäten erfüllen. Das heißt, Sie sollten nicht davon ausgehen, dass zB
1 + 2
gleich2 + 1
oder1 + (2 + 3)
gleich ist(1 + 2) + 3
.Sie können davon ausgehen, dass die Zahlen in der Eingabe 2 31 - 1 = 2147483647 nicht überschreiten .
Diese Regeln sollen sicherstellen, dass die korrekte Ausgabe durch die Eingabe eindeutig definiert wird.
Beispiele:
Hier sind einige gültige Eingabeausdrücke und die entsprechenden Ausgaben, dargestellt in der Form "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 + * -"
(Zumindest hoffe ich, dass all dies richtig ist. Ich habe die Konvertierung von Hand durchgeführt, sodass sich Fehler eingeschlichen haben könnten.)
Die folgenden Eingaben sind alle ungültig. Es spielt keine Rolle, was Ihre Lösung tut, wenn sie angegeben wird (obwohl es natürlich sinnvoller ist, z. B. eine Fehlermeldung zurückzugeben, als beispielsweise unendlich viel Speicherplatz zu verbrauchen):
""
"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".1 2 3 4 + *
?Antworten:
Muschelutensilien - 60 Zeichen
Die verschiedenen Probleme wurden behoben, aber es wurde viel länger :(
quelle
sed -re's/[:@iKWr]+/ /g'
behebt den Fehler bei 1 Charakter.C
250245236193185 ZeichenHier ist eine lesbare Version der Quelle ohne Golf, die immer noch die grundlegende Logik widerspiegelt. Es ist eigentlich ein ziemlich einfaches Programm. Die einzige wirkliche Aufgabe besteht darin, einen Operator mit niedriger Assoziativität auf einen Stapel zu verschieben, wenn ein Operator mit hoher Assoziativität angetroffen wird, und ihn dann am "Ende" dieses Unterausdrucks wieder zu entfernen.
quelle
if
. ZBif(!*p||*p==41)return p;s[++t]=*p;}
->return*p&&*p-41?s[++t]=*p:p;
*f(p,s)char*p,s;{
if
Test fehlschlägt. 2. Ich weiß, aber bei der K & R-Funktion decls zeichne ich die Linie. Ich kann einfach nicht zu ihnen zurückkehren.}}
undfor
. Aber hier ist eine Verbesserung:printf(" %ld"+!a,...
p
global machen sollten (der rekursive Anruf weist nur den Angerufenenp
dem Anrufer zurück). Dann tu esf(p=gets(b))
.Bash w / Haskell w /
C Präprozessorsed, 180195198275Endlich ist es nicht mehr länger als die C-Lösung. Das entscheidende Haskell-Teil ist fast so faul wie die bc-Lösung ...
Übernimmt Eingaben als Befehlszeilenparameter. Eine Datei
w
mit einigen ghc-Warnmeldungen wird erstellt, wenn Sie diese Änderung nicht möchtenrunghc 2>/dev/null
.quelle
Python 2,
290272268250243238 BytesJetzt endlich kürzer als die JS Antwort!
Dies ist ein vollständiges Programm, das eine grundlegende Implementierung des Rangierbahnhof-Algorithmus verwendet . Die Eingabe erfolgt in Anführungszeichen und das Ergebnis wird an ausgegeben
STDOUT
.Probieren Sie es online!
Erläuterung:
Als erstes müssen wir die Eingabe in Token konvertieren. Wir verwenden dazu alle Übereinstimmungen des regulären Ausdrucks
\d+|\S
, die grob in "eine beliebige Gruppe von Ziffern und ein beliebiges Nicht-Leerzeichen" übersetzt wurden. Dadurch werden Leerzeichen entfernt, benachbarte Ziffern als einzelne Token analysiert und Operatoren separat analysiert.Für den Rangierbahnhof-Algorithmus müssen vier verschiedene Tokentypen verarbeitet werden:
(
- Linke Klammer)
- Rechte Klammer+-*/
- Betreiber9876543210
- Numerische LiteraleZum Glück sind die ASCII-Codes in der angegebenen Reihenfolge gruppiert, sodass wir den Tokentyp
(t>'/')+(t>')')+(t>'(')
anhand des Ausdrucks berechnen können. Dies ergibt 3 für Ziffern, 2 für Operatoren, 1 für eine rechte Klammer und 0 für eine linke Klammer.Mit diesen Werten indizieren wir das große Tupel after
exec
, um das entsprechende Snippet basierend auf dem Token-Typ auszuführen. Dies ist für jeden Token anders und das Rückgrat des Rangierbahnhof-Algorithmus. Es werden zwei Listen (als Stapel) verwendet:O
(Operationsstapel) undB
(Ausgabepuffer). Nachdem alle Token ausgeführt wurden, werden die verbleibenden Operatoren auf demO
Stapel mit dem Ausgabepuffer verknüpft und das Ergebnis gedruckt.quelle
Prolog (SWI-Prolog) , 113 Bytes
Probieren Sie es online!
SWI Prolog verfügt über eine viel bessere Anzahl an integrierten Funktionen als GNU Prolog, wird jedoch durch die ausführliche Syntax von Prolog noch etwas zurückgehalten.
Erläuterung
term_to_atom
Wenn Sie rückwärts ablaufen, wird ein (als Atom gespeicherter) Infix-Notationsausdruck in einen Analysebaum geparst (unter Beachtung der üblichen Vorrangregeln und Löschen von führenden Nullen und Leerzeichen). Anschließend verwenden wir das Hilfsprädikatc
, um eine strukturelle Rekursion über den Analysebaum durchzuführen und diese zunächst in die Postfix-Notation umzuwandeln.quelle
Javascript (ES6), 244 Byte
Beispiel:
Call:
f('0-1+(2-3)*4-5*(6-(7+8)/9+10)')
Output:
0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -
(mit einem Leerzeichen)Erläuterung:
quelle
R, 142 Bytes
R ist in der Lage, sich selbst zu analysieren. Statt das Rad neu zu erfinden, setzen wir den Parser einfach in Betrieb, der die Präfixnotation ausgibt, und verwenden eine rekursive Funktion, um auf die Postfixnotation umzuschalten.
Das
p
Argument ist, die Verwendung von Nicht-Standard-Auswertungen zu kontrollieren (der Fluch von R-Programmierern überall), und es gibt ein paar Extrasif
, um die Ausgabe von Klammern zu kontrollieren (die wir vermeiden wollen).Eingang:
(0-1+(2-3)*4-5*(6-(7+8)/9+10))
Ausgabe:
0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -
Eingang:
(((((1))) + (2)))
Ausgabe:
1 2 +
Als Bonus funktioniert es mit beliebigen Symbolen und beliebigen vordefinierten Funktionen mit bis zu zwei Argumenten:
Eulers Identität
Eingang:
e^(i*pi)-1
Ausgabe:
e i pi * ^ 1 -
Dividenden von 13 zwischen 1 und 100
Eingang:
which(1:100 %% 13 == 0)
Ausgabe:
1 100 : 13 %% 0 == which
Lineare Regression des Gewichts von Hühnchen als Funktion der Zeit
Eingang:
summary(lm(weight~Time, data=ChickWeight))
Ausgabe:
weight Time ~ ChickWeight lm summary
Das letzte Beispiel liegt vielleicht etwas außerhalb des Anwendungsbereichs des OP, verwendet aber die Postfix-Notation, also ...
quelle