Quand j'ai vu le titre de cette question fermée , j'ai pensé que cela ressemblait à un défi de golf de code intéressant. Alors laissez-moi le présenter comme tel:
Défi:
Écrivez un programme, une expression ou un sous-programme qui, étant donné une expression arithmétique en notation infixe , comme 1 + 2
, génère la même expression en notation postfixe , c'est-à-dire 1 2 +
.
(Remarque: un défi similaire a été publié plus tôt en janvier. Cependant, je pense que les deux tâches sont suffisamment différentes en détail pour justifier ce défi distinct. De plus, je n'ai remarqué l'autre fil après avoir tapé tout ci-dessous, et je préfère pas simplement jeter le tout.)
Contribution:
L'entrée se compose d'une expression arithmétique infixée valide consistant en nombres (entiers non négatifs représentés comme des séquences d'un ou plusieurs chiffres décimaux), équilibré entre parenthèses pour indiquer une sous - expression regroupés, et les quatre binaires infix opérateurs +
, -
, *
et /
. N'importe lequel d'entre eux peut être séparé (et l'expression entière entourée) par un nombre arbitraire de caractères d'espace, qui doivent être ignorés. 1
Pour ceux qui aiment les grammaires formelles, voici une grammaire simple de type BNF qui définit les entrées valides. Pour des raisons de concision et de clarté, la grammaire n'inclut pas les espaces facultatifs, qui peuvent apparaître entre deux jetons (autres que les chiffres d'un nombre):
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 Le seul cas où la présence d'espaces peut affecter l'analyse est lorsqu'ils séparent deux nombres consécutifs; cependant, puisque deux nombres non séparés par un opérateur ne peuvent pas apparaître dans une expression d'infixe valide, ce cas ne peut jamais se produire dans une entrée valide.
Sortie:
La sortie doit être une expression suffixe équivalente à l'entrée. L'expression de sortie doit contenir que des nombres et les opérateurs, avec un seul caractère d'espace entre chaque paire de jetons adjacents, comme dans la grammaire ci - après (qui ne comprennent les espaces) 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 Encore pour plus de simplicité, la number
production dans cette grammaire admet des nombres avec des zéros en tête, même s'ils sont interdits dans la sortie par les règles ci-dessous.
Priorité des opérateurs:
En l'absence de parenthèses, les règles de priorité suivantes s'appliquent:
- Les opérateurs
*
et/
ont une priorité plus élevée que+
et-
. - Les opérateurs
*
et/
ont une priorité égale les uns aux autres. - Les opérateurs
+
et-
ont une priorité égale les uns aux autres. - Tous les opérateurs sont associatifs à gauche.
Par exemple, les deux expressions suivantes sont équivalentes:
1 + 2 / 3 * 4 - 5 + 6 * 7
((1 + ((2 / 3) * 4)) - 5) + (6 * 7)
et ils devraient tous deux produire la sortie suivante:
1 2 3 / 4 * + 5 - 6 7 * +
(Ce sont les mêmes règles de priorité que dans le langage C et dans la plupart des langues qui en dérivent. Elles ressemblent probablement aux règles qui vous ont été enseignées au primaire, sauf peut-être pour la priorité relative de *
et /
.)
Règles diverses:
Si la solution donnée est une expression ou un sous-programme, l'entrée doit être fournie et la sortie renvoyée sous la forme d'une chaîne unique. Si la solution est un programme complet, elle doit lire une ligne contenant l'expression infixe de l'entrée standard et imprimer une ligne contenant la version postfixe sur la sortie standard.
Les nombres dans l'entrée peuvent inclure des zéros non significatifs. Les nombres dans la sortie ne doivent pas avoir de zéros en tête (à l'exception du nombre 0, qui doit être sorti comme
0
).Vous n'êtes pas censé évaluer ou optimiser l'expression en aucune façon. En particulier, vous ne devez pas supposer que les opérateurs satisfont nécessairement toutes les identités associatives, commutatives ou autres identités algébriques. Autrement dit, vous ne devez pas supposer que, par exemple,
1 + 2
est égal2 + 1
ou1 + (2 + 3)
égal à(1 + 2) + 3
.Vous pouvez supposer que les nombres en entrée ne dépassent pas 2 31 - 1 = 2147483647.
Ces règles visent à garantir que la sortie correcte est définie de manière unique par l'entrée.
Exemples:
Voici quelques expressions d'entrée valides et les sorties correspondantes, présentées sous la forme "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 + * -"
(Au moins, j'espère que tout cela est correct; j'ai fait la conversion à la main, donc des erreurs auraient pu se glisser.)
Juste pour être clair, les entrées suivantes sont toutes invalides; il ne pas d' importance ce que votre solution ne se les donne (bien que, bien sûr, par exemple , renvoyer un message d'erreur est plus agréable que, par exemple, la consommation d' une quantité infinie de mémoire):
""
"x"
"1 2"
"1 + + 2"
"-1"
"3.141592653589793"
"10,000,000,001"
"(1 + 2"
"(1 + 2)) * (3 / (4)"
1 2 3 4 +
signifie «1 + 2 + 3 + 4».1 2 3 4 + *
?Réponses:
Shell utils - 60 caractères
Correction des divers problèmes, mais cela a pris beaucoup plus de temps :(
la source
sed -re's/[:@iKWr]+/ /g'
corrige au coût de 1 caractère.C,
250245236193185 caractèresVoici une version lisible de la source non golfée, qui reflète toujours la logique de base. C'est en fait un programme assez simple. Le seul vrai travail qu'il a à faire est de pousser un opérateur à faible associativité sur une pile lorsqu'un opérateur à haute associativité est rencontré, puis de le réactiver à la "fin" de cette sous-expression.
la source
if
. Par exempleif(!*p||*p==41)return p;s[++t]=*p;}
->return*p&&*p-41?s[++t]=*p:p;
*f(p,s)char*p,s;{
if
test échoue. 2. Je sais, mais la fonction K&R decls est l'endroit où je trace la ligne. Je ne peux tout simplement pas y revenir.}}
etfor
. Mais voici une amélioration:printf(" %ld"+!a,...
p
global (l'appel récursif assigne simplementp
l'appelé à l'appelant). Alors faisf(p=gets(b))
.Bash avec Haskell avec
Préprocesseur Csed, 180195198275Enfin, elle n'est plus plus longue que la solution C. La partie cruciale de Haskell est presque aussi paresseuse que la solution bc ...
Prend l'entrée comme paramètres de ligne de commande. Un fichier
w
contenant des messages d'avertissement ghc sera créé si vous n'aimez pas cette modificationrunghc 2>/dev/null
.la source
Python 2,
290272268250243238 octetsMaintenant enfin plus court que la réponse JS!
Il s'agit d'un programme complet qui utilise une implémentation de base de l' algorithme de triage . L'entrée est donnée sous forme de chaîne entre guillemets et le résultat est imprimé dans
STDOUT
.Essayez-le en ligne!
Explication:
La première chose que nous devons faire est de convertir l'entrée en jetons. Nous le faisons en utilisant en trouvant toutes les correspondances de l'expression régulière
\d+|\S
, traduit grossièrement « tout groupe de chiffres, et un caractère non-espace ». Cela supprime les espaces, analyse les chiffres adjacents comme des jetons uniques et analyse les opérateurs séparément.Pour l'algorithme de triage, il y a 4 types de jetons distincts que nous devons gérer:
(
- Parenthèse gauche)
- Parenthèse droite+-*/
- Les opérateurs9876543210
- Littéraux numériquesHeureusement, les codes ASCII de ceux-ci sont tous regroupés dans l'ordre indiqué, nous pouvons donc utiliser l'expression
(t>'/')+(t>')')+(t>'(')
pour calculer le type de jeton. Il en résulte 3 pour les chiffres, 2 pour les opérateurs, 1 pour une parenthèse droite et 0 pour une parenthèse gauche.En utilisant ces valeurs, nous indexons dans le grand tuple après
exec
pour obtenir l'extrait correspondant à exécuter, en fonction du type de jeton. Ceci est différent pour chaque jeton et constitue l'épine dorsale de l'algorithme de triage. Deux listes sont utilisées (sous forme de piles):O
(pile d'opérations) etB
(tampon de sortie). Une fois tous les jetons exécutés, les opérateurs restants de laO
pile sont concaténés avec le tampon de sortie et le résultat est imprimé.la source
Prolog (SWI-Prolog) , 113 octets
Essayez-le en ligne!
SWI Prolog a pour cela un ensemble bien mieux intégré que GNU Prolog, mais il est encore quelque peu freiné par la verbosité de la syntaxe de Prolog.
Explication
term_to_atom
, si elle est exécutée à l'envers, analysera une expression de notation infixée (stockée sous forme d'atome) dans un arbre d'analyse (en respectant les règles de priorité habituelles et en supprimant les zéros et les espaces). Nous utilisons ensuite le prédicat d'aidec
pour effectuer une récursion structurelle sur l'arbre d'analyse, en convertissant en notation postfixe en profondeur d'abord.la source
Javascript (ES6), 244 octets
Exemple:
Appel:
f('0-1+(2-3)*4-5*(6-(7+8)/9+10)')
Sortie:
0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -
(avec un espace de fin)Explication:
la source
R, 142 octets
R est capable de s'auto-analyser, donc plutôt que de réinventer la roue, nous mettons simplement l'analyseur au travail, qui génère une notation de préfixe, et utilisons une fonction récursive pour la basculer en notation postfixée.
L'
p
argument est de contrôler l'utilisation de l'évaluation non standard (le fléau des programmeurs R partout), et il y a quelquesif
s supplémentaires pour contrôler la sortie des crochets (que nous voulons éviter).Contribution:
(0-1+(2-3)*4-5*(6-(7+8)/9+10))
Sortie:
0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -
Contribution:
(((((1))) + (2)))
Sortie:
1 2 +
En prime, il fonctionne avec des symboles arbitraires et toutes les fonctions prédéfinies avec jusqu'à deux arguments:
L'identité d'Euler
Contribution:
e^(i*pi)-1
Sortie:
e i pi * ^ 1 -
Dividendes de 13 entre 1 et 100
Contribution:
which(1:100 %% 13 == 0)
Sortie:
1 100 : 13 %% 0 == which
Régression linéaire du poids du poulet en fonction du temps
Contribution:
summary(lm(weight~Time, data=ChickWeight))
Sortie:
weight Time ~ ChickWeight lm summary
Le dernier exemple est peut-être un peu en dehors de la portée de l'OP, mais il utilise la notation postfixe, donc ...
la source