Herausforderung
Hier ist die Herausforderung (meiner eigenen Erfindung, obwohl ich mich nicht wundern würde, wenn sie zuvor an anderer Stelle im Internet erschienen wäre).
Schreiben Sie eine Funktion, die ein einzelnes Argument, das eine Zeichenfolgendarstellung eines einfachen mathematischen Ausdrucks ist, als Gleitkommawert auswertet. Ein "einfacher Ausdruck" kann eine der folgenden Angaben enthalten: positive oder negative Dezimalzahlen, + , - , * , / , ( , ) . Ausdrücke verwenden die (normale) Infixnotation . Bediener sollten in der Reihenfolge bewertet werden, in der sie erscheinen, dh nicht wie in BODMAS , obwohl Klammern natürlich korrekt beachtet werden sollten. Die Funktion sollte für jedes das richtige Ergebnis zurückgebenmöglicher Ausdruck dieser Form. Die Funktion muss jedoch keine fehlerhaften Ausdrücke verarbeiten (dh solche mit schlechter Syntax).
Beispiele für Ausdrücke:
1 + 3 / -8 = -0.5 (No BODMAS) 2*3*4*5+99 = 219 4 * (9 - 4) / (2 * 6 - 2) + 8 = 10 1 + ((123 * 3 - 69) / 100) = 4 2.45/8.5*9.27+(5*0.0023) = 2.68...
Regeln
Ich erwarte hier irgendeine Form von "Betrug" / List, also lassen Sie mich bitte davor warnen! Unter Betrug verstehe ich die Verwendung der eval
oder einer gleichwertigen Funktion in dynamischen Sprachen wie JavaScript oder PHP oder das gleichzeitige Kompilieren und Ausführen von Code im laufenden Betrieb. (Ich denke, meine Spezifikation von "no BODMAS" hat dies jedoch so ziemlich garantiert.) Abgesehen davon gibt es keine Einschränkungen. Ich erwarte hier einige Regex-Lösungen, aber es wäre schön, mehr als nur das zu sehen.
Jetzt bin ich hauptsächlich an einer C # /. NET-Lösung interessiert, aber jede andere Sprache wäre auch vollkommen akzeptabel (insbesondere F # und Python für die funktionalen / gemischten Ansätze). Ich habe noch nicht entschieden, ob ich die kürzeste oder genialste Lösung (zumindest für die Sprache) als Antwort akzeptieren werde, aber ich würde jede Form von Lösung in jeder Sprache begrüßen , außer dem, was ich gerade oben verboten habe !
Meine Lösung
Ich habe jetzt meine C # -Lösung hier veröffentlicht (403 Zeichen). Update: Meine neue Lösung hat die alte mit 294 Zeichen mit Hilfe eines schönen Regex deutlich übertroffen! Ich hatte den Verdacht, dass dies von einigen der Sprachen mit leichterer Syntax (insbesondere der funktionalen / dynamischen) leicht übertroffen wird, und habe mich als richtig erwiesen, aber ich wäre neugierig, ob jemand dies in C # noch schlagen könnte.
Aktualisieren
Ich habe bereits einige sehr clevere Lösungen gesehen. Vielen Dank an alle, die einen gepostet haben. Obwohl ich noch keinen von ihnen getestet habe, werde ich den Leuten vertrauen und davon ausgehen, dass sie zumindest mit allen angegebenen Beispielen arbeiten.
Nur für den Hinweis, Wiedereintritt (dh Thread-Sicherheit) ist keine Voraussetzung für die Funktion, obwohl es ein Bonus ist.
Format
Bitte posten Sie alle Antworten zum leichteren Vergleich im folgenden Format:
Sprache
Anzahl von Charakteren: ???
Vollständig verschleierte Funktion:
(code here)
Klare / halbverschleierte Funktion:
(code here)
Alle Hinweise zum Algorithmus / clevere Verknüpfungen.
quelle
Antworten:
Perl (keine Bewertung)
Anzahl der Zeichen:
167106 (siehe unten für die 106-Zeichen-Version)Vollständig verschleierte Funktion: (167 Zeichen, wenn Sie diese drei Zeilen zu einer verbinden)
Klare / deobfuscated Version:
Ich hatte die Regeln anfangs falsch verstanden, also hatte ich eine Version mit "eval" eingereicht. Hier ist eine Version ohne.
Die neueste wenig Einsicht kam , als ich erkennen , dass der letzte Oktalziffer in dem Zeichencodes für
+
,-
,/
, und*
ist anders, Und dasord(undef)
ist 0. Auf diese Weise können Sie mir die Dispatch - Tabelle aufgebaut@a
als ein Array, und nur invoke den Code bei der Lage7 & ord($3)
.Es gibt einen offensichtlichen Punkt, an dem Sie einen weiteren Charakter rasieren können - wechseln Sie
q""
in''
-, aber das würde das Ausschneiden und Einfügen in die Shell erschweren.Noch kürzer
Anzahl der Zeichen:
124106Unter Berücksichtigung der Änderungen durch Ephemient sind es jetzt nur noch 124 Zeichen: (Verbinden Sie die beiden Zeilen zu einer)
Noch kürzer
Anzahl der Zeichen:
110106Die Rubinlösung unten treibt mich weiter, obwohl ich ihre 104 Zeichen nicht erreichen kann:
Ich musste nachgeben und benutzen
''
. Dieser Rubin-send
Trick ist wirklich nützlich für dieses Problem.Wasser aus einem Stein drücken
Anzahl der Zeichen: 106
Eine kleine Verzerrung, um die Überprüfung durch Null zu vermeiden.
Hier ist das Testkabel für diese Funktion:
quelle
Assembler
427 Bytes
Verschleiert, zusammengebaut mit dem exzellenten A86 zu einer ausführbaren .com-Datei:
EDIT: Unverschmierte Quelle:
quelle
Rubin
Anzahl der Zeichen: 103
Dies ist eine
nicht rekursiveVersion der Lösung von The Wicked Flea. Unterausdrücke in Klammern werden von unten nach oben statt von oben nach unten ausgewertet.Bearbeiten : Durch das Konvertieren des 'while' in eine bedingte + Schwanzrekursion wurden einige Zeichen gespeichert, sodass es nicht mehr nicht rekursiv ist (obwohl die Rekursion semantisch nicht erforderlich ist).
Bearbeiten : Das Ausleihen von Daniel Martins Idee, die regulären Ausdrücke zusammenzuführen, spart weitere 11 Zeichen!
Edit : Diese Rekursion ist noch nützlicher als ich zuerst dachte!
x.to_f
kann wie folgt umgeschrieben werdene(x)
, wennx
zufällig eine einzelne Nummer enthalten ist.Bearbeiten : Wenn Sie '
or
' anstelle von '||
' verwenden, können zwei Klammern entfernt werden.Lange Version:
quelle
C (VS2005)
Anzahl der Zeichen: 1360
Missbrauch des Präprozessors und Warnungen für ein lustiges Code-Layout (scrollen Sie nach unten, um zu sehen):
quelle
Visual Basic.NET
Anzahl der Zeichen: 9759
Ich bin selbst eher ein Bowler.
HINWEIS: Berücksichtigt keine verschachtelten Klammern. Auch ungetestet, aber ich bin mir ziemlich sicher, dass es funktioniert.
quelle
Haskell
Anzahl der Zeichen: 182
Kein Versuch der Klugheit, nur etwas Komprimierung: 4 Zeilen, 312 Bytes.
Und jetzt wirklich in den Golfgeist kommen, 3 Zeilen und 182 Bytes:
Explodiert:
quelle
Python
Anzahl der Zeichen: 237
Vollständig verschleierte Funktion:
Klare / halbverschleierte Funktion:
quelle
-(1.0)
auch aus, also keine Sorge! Ich werde die Frage klären. Wie auch immer, es scheint eine sehr clevere Lösung zu sein - ich versuche immer noch herauszufinden, wie es funktioniert (ich kenne Python nicht genau). Wenn Sie eine kurze Erklärung hinzufügen könnten, wäre dies sehr dankbar.Fortran 77 (Gfortran-Dialekt, jetzt mit G77-Unterstützung)
Anzahl der Zeichen: 2059
Verschleierte Version:
Klare Version: (3340 Zeichen mit Gerüst)
Anmerkungen Diese bearbeitete Version ist eher böse als mein erster Versuch. Gleicher Algorithmus, aber jetzt inline mit einem schrecklichen Gewirr von
goto
s. Ich habe die Co-Routinen aufgegeben, verwende jetzt aber einige Varianten von berechneten Zweigen. Alle Fehlerprüfungen und Berichte wurden entfernt, aber diese Version wird stillschweigend von einigen Klassen unerwarteter Zeichen in der Eingabe wiederhergestellt. Diese Version wird auch mit g77 kompiliert.Die primären Grenzen sind immer noch die starre Formatierung von fortran, lange und allgegenwärtige Schlüsselwörter und einfache Grundelemente.
quelle
C99
Anzahl der Zeichen: 239 ( 209 siehe unten )
komprimierte Funktion:
dekomprimierte Funktion:
Funktion ist nicht wiedereintrittsfähig.
EDIT von Chris Lutz : Ich hasse es, den Code eines anderen Mannes mit Füßen zu treten, aber hier ist eine 209- Zeichen-Version:
Lesbar (gut, nicht wirklich gut lesbar, aber dekomprimiert):
Ja,
f()
ist ein Makro, keine Funktion, aber es funktioniert. In der lesbaren Version wurde ein Teil der Logik neu geschrieben, aber nicht neu angeordnet (wieo != '+'
anstelle vono - '+'
), sondern es handelt sich ansonsten nur um eine eingerückte (und vorverarbeitete) Version der anderen. Ich versuche immer wieder, dasif(!o|o==41)return a;
Teil in derfor()
Schleife zu vereinfachen , aber es macht es nie kürzer. Ich glaube immer noch, dass es möglich ist, aber ich bin mit dem Golfen fertig. Wenn ich an dieser Frage weiter arbeite, wird sie in der Sprache sein, die nicht benannt werden darf .quelle
Common Lisp
(SBCL)
Anzahl der Zeichen: 251
Richtige Version (387 Zeichen):
Die Eingabe ist eine Form
w()
, die ein Zeichenfolgenargument akzeptiert. Es verwendet den Trick, dass sich Zahlen / Operanden und Operatoren im Muster NONON befinden ... und wertet alle Operanden rekursiv aus, wodurch das Verschachteln sehr billig wird. ;)quelle
JavaScript (nicht IE-kompatibel)
Anzahl der Zeichen: 268/260
Vollständig verschleierte Funktion:
In JavaScript 1.8 (Firefox 3+) können Sie einige Zeichen mithilfe von Ausdrucksschließungen speichern:
Klare / halbverschleierte Funktion:
Keine der beiden Versionen funktioniert im IE, da für die Zeichenfolge Subskriptionen im Array-Stil verwendet werden. Wenn Sie beide Vorkommen von
x[0]
durch ersetzenx.charAt(0)
, sollte das erste überall funktionieren.Ich habe seit der ersten Version einige weitere Zeichen ausgeschnitten, indem ich Variablen in Funktionsparameter umgewandelt und eine andere if-Anweisung durch den bedingten Operator ersetzt habe.
quelle
C # mit Regex Love
Anzahl der Zeichen: 384
Vollständig verschleiert:
Nicht verschleiert:
Nutzt die Regex- Ausgleichsgruppenfunktion von .NET .
quelle
PHP
Anzahl der Zeichen: 284
verschleiert:
lesbar:
Sollte mit jeder gültigen Eingabe funktionieren (einschließlich negativer Zahlen und beliebiger Leerzeichen)
quelle
preg_replace()
mit deme
Modifikator würden Sie einige weitere Bytes sparen.SQL (SQL Server 2008)
Anzahl der Zeichen: 4202
Vollständig verschleierte Funktion:
Klare / halbverschleierte Funktion:
Es ist nicht am kürzesten. Aber ich denke, dass es für SQL sehr flexibel ist. Es ist einfach, neue Operatoren hinzuzufügen. Es ist einfach, die Priorität der Bediener zu ändern.
quelle
F #
Anzahl der Zeichen: 327
OP suchte nach einer F # -Version, hier ist sie. Kann viel schöner gemacht werden, da ich hier einen Schiedsrichter missbrauche , um Charaktere zu speichern. Es behandelt die meisten Dinge wie - (1.0) , 3 - -3 und sogar 0 - .5 usw.
quelle
J.
Anzahl der Zeichen: 208
Nach Jeff Mosers Kommentar wurde mir klar, dass ich diese Sprache völlig vergessen hatte ... Ich bin kein Experte, aber mein erster Versuch verlief ziemlich gut.
Es ist ein bisschen nervig, abbilden zu müssen
x/y
und-z
in J'sx%y
und_z
. Ohne das könnten vielleicht 50% dieses Codes verschwinden.quelle
Python (ohne etwas zu importieren)
Anzahl der Zeichen: 222
Ich habe viele Tricks aus Daves Antwort gestohlen, aber ich habe es geschafft, einige weitere Charaktere zu rasieren.
Kommentierte Version:
quelle
C #
Anzahl der Zeichen: 403
Also hier ist meine Lösung ... Ich warte immer noch darauf, dass jemand eine in C # veröffentlicht, die sie schlagen kann. (Marc Gravell war nah dran und kann es nach etwas mehr Basteln noch besser machen als ich.)
Vollständig verschleierte Funktion:
Halbverschleierte Funktion:
Hier ist nichts allzu Kluges los, wie es scheint. Die Funktion hat jedoch den Vorteil, dass sie wieder eintritt (dh threadsicher).
Ich bin auch ziemlich zufrieden mit der Anzahl der Zeichen, da es in C # geschrieben ist (gültig 1.0, 2.0 und 3.0, glaube ich).
quelle
Hier kommt noch einer:
Shell-Skript (mit sed + awk)
Anzahl der Zeichen: 295
verschleiert:
lesbar
Prüfung:
Ergebnis:
quelle
MATLAB (v7.8.0)
Anzahl der Zeichen: 239
Verschleierte Funktion:
Löschfunktion (er):
Prüfung:
Synopsis: Eine Mischung aus regulären Ausdrücken und Rekursion. So ziemlich das Beste, was ich bisher konnte, ohne zu schummeln und EVAL zu benutzen.
quelle
Rubin
Anzahl der Zeichen: 170
Verschleiert:
Lesbar:
Es gibt keine wirkliche Verschleierung zu dieser, die ich frisch gepostet habe, da sie sich stark von meiner ersten unterscheidet. Ich hätte das von Anfang an sehen sollen. Der Prozess ist ein sehr einfacher Eliminierungsprozess: Suchen und lösen Sie das höchste Klammerpaar (das am meisten verschachtelte) in eine Zahl, bis keine weiteren mehr gefunden werden, und lösen Sie dann alle vorhandenen Zahlen und Operationen im Ergebnis auf. Und während ich Aussagen in Klammern auflöse, werden alle Doppelstriche entfernt (Float.to_f weiß nicht, was ich damit anfangen soll).
Es unterstützt also positive und negative Zahlen (+3, 3, -3) und sogar negierte Unterausdrücke in der Klammer nur in der Reihenfolge der Verarbeitung. Die einzige kürzere Implementierung ist die Perl-Implementierung (ohne Bewertung).
Bearbeiten: Ich bin immer noch auf der Jagd nach Perl, aber dies ist derzeit die zweitkleinste Antwort. Ich habe es mit Änderungen an der zweiten Regex und durch Ändern der Behandlung der Zeichenfolge als destruktiv verkleinert (ersetzt die alte Zeichenfolge). Dadurch musste die Zeichenfolge nicht mehr dupliziert werden. Ich stellte fest, dass dies nur ein neuer Zeiger auf die Zeichenfolge ist. Beim Umbenennen der Funktion in s von lösen wurden einige Zeichen gespeichert.
quelle
Python mit regulären Ausdrücken
Anzahl der Zeichen: 283
Vollständig verschleierte Funktion:
Nicht verschleiert:
Ich wollte sehen, ob ich die anderen Python-Lösungen mit regulären Ausdrücken schlagen kann.
Konnte nicht.
Der reguläre Ausdruck, den ich verwende, erstellt eine Liste von Paaren (val, op), in denen nur ein Element in jedem Paar gültig ist. Der Rest des Codes ist ein eher standardmäßiger stapelbasierter Parser mit einem tollen Trick, die obersten 3 Zellen im Stapel durch das Ergebnis der Berechnung unter Verwendung der Python-Listenzuweisungssyntax zu ersetzen. Damit dies mit negativen Zahlen funktioniert, sind nur zwei zusätzliche Zeichen erforderlich (-? In der Regex).
quelle
zip
stoppt am Ende der kürzeren Liste.Python
Anzahl der Zeichen: 382
Eine weitere Python-Lösung, bei der häufig reguläre Ausdrücke ersetzt werden. Bei jedem Durchlauf durch die Schleife werden die einfachsten Ausdrücke berechnet und die Ergebnisse wieder in die Zeichenfolge eingefügt.
Dies ist der nicht verschleierte Code, es sei denn, Sie betrachten reguläre Ausdrücke als verschleiert.
Hatte diese Idee gerade als ich mich umdrehte und konnte sie nicht loslassen, bis ich sie aufgeschrieben und zum Laufen gebracht hatte.
quelle
C #
Anzahl der Zeichen: 396 (aktualisiert)
(aber der Test, den Sie mit "/ -8" hinzugefügt haben, schlägt fehl, und ich bin nicht geneigt, ihn zu beheben ...
Von:
quelle
Python
Anzahl der Zeichen: 235
Vollständig verschleierte Funktion:
Halbverschleiert:
FWIW, die n + 1. Python-Lösung. Bei einem offensichtlichen Missbrauch von try - außer ich verwende einen Trial-and-Error-Ansatz. Es sollte alle Fälle richtig behandeln, einschließlich Sachen wie
-(8)
,--8
undg('-(1 - 3)')
. Es ist wieder eintretend. Ohne Unterstützung für den--
Fall, den viele Implementierungen nicht unterstützen, liegt der Wert bei 217 Zeichen (siehe vorherige Überarbeitung).Vielen Dank für eine interessante Stunde an einem Sonntag und weitere 30 Minuten am Montag. Danke an krubo für sein nettes dikt.
quelle
Rubin
Anzahl von Charakteren:
217179Dies ist die bisher kürzeste Rubinlösung (eine stark auf RegExp basierende Lösung liefert falsche Antworten, wenn die Zeichenfolge nur wenige Gruppen von Klammern enthält).-- Nicht mehr wahr. Lösungen, die auf Regex und Substitution basieren, sind kürzer. Dieser basiert auf einem Stapel von Akkumulatoren und analysiert den gesamten Ausdruck von links nach rechts. Es ist wiedereintrittsfähig und ändert die Eingabezeichenfolge nicht. Es könnte beschuldigt werden, gegen die Regeln der Nichtverwendung verstoßen zu habeneval
, da esFloat
Methoden mit identischen Namen wie ihre mathematischen Mnemoniken (+, -, /, *) aufruft .Verschleierter Code (alte Version, unten optimiert) :
Mehr verschleierter Code:
Code reinigen:
quelle
Ruby 1.8.7
Anzahl der Zeichen: 620
Versuchen Sie, meine Implementierung zu vereinfachen. Es ist das erste Mal in meinem Leben, dass ich einen Ausdrucksparser schreibe! Ich garantiere, dass es nicht das Beste ist.
Verschleiert:
Lesbar:
quelle
Ruby 1.9
(wegen der Regex)
Anzahl der Zeichen: 296
BEARBEITEN: Beinhaltet Martins Optimierung.
quelle
SNOBOL4
Anzahl der Zeichen: 232
Dies ist ein Halbbetrüger. Es verwendet
code()
(eine Variante von eval), um sich selbst zu dekomprimieren, aber nicht, um den Eingabeausdruck auszuwerten.Entdeckte Version, ohne
code
:Strategie:
spaces
)paren
)'('
oder am Anfang der Zeichenfolge vorangestellt wirdBeispiel:
1 + (2 * 3) + 4
1+(2*3)+4
[spaces
]1+(6)+4
[mul
]1+6+4
[paren
]7+4
[add
]11
[add
]quelle
C #
Anzahl der Zeichen: 355
Ich nahm Noldorins Antwort und änderte sie, also gib Noldorin 99% der Gutschrift dafür. Das Beste, was ich mit dem verwendeten Algorithmus machen konnte, waren 408 Zeichen. Siehe Noldorins Antwort für die klarere Codeversion.
Änderungen vorgenommen:
Ändern Sie die Zeichenvergleiche, um sie mit den Zahlen zu vergleichen.
Einige Standarddeklarationen wurden entfernt und derselbe Deklarationstyp kombiniert.
Einige der if-Anweisungen wurden überarbeitet.
Bearbeiten: Es wurde von 361 auf 355 weiter heruntergefahren, indem eine der Rückgabeanweisungen entfernt wurde.
quelle