J'ai une chaîne qui est une équation mathématique, mais avec des fonctions personnalisées. J'ai besoin de trouver toutes ces fonctions et de les remplacer avec du code.
Par exemple, j'ai une chaîne: p> Je veux le code qui remplacera (dire) < Code> F2 (x, y) code> avec Il serait idéal si des fonctions imbriquées étaient prises en charge, comme dans l'exemple. Cependant, il serait toujours utile que la nidification n'était pas prise en charge. P> Si que je comprends à partir de sujets similaires, vous pouvez être effectué à l'aide d'un module compilateur tel que J'ai besoin de remplacer la substitution et ensuite la chaîne être utilisé dans un autre programme. L'évaluation n'est pas nécessaire. P> p> x + y ^ 2 code> et
f1 (x, y) code> avec
sin (x + y) < /Code >.
compiler.parse (EQ) code>. Comment puis que je puisse travailler avec AST objet créé par
compiler.parse (EQ) code> pour reconstruire mon chaîne en arrière, remplacer toutes les fonctions trouvées? P>
6 Réponses :
Quel est votre objectif à long terme? Est-ce d'évaluer la fonction ou d'effectuer simplement une substitution? Dans le premier cas, vous pouvez simplement essayer ceci (note que si tu veux Pour remplacer les fonctions et récupérer la version modifiée, vous devrez effectivement recourir à une sorte d'analyseur ast. Soyez prudent avec l'utilisation de F1 code> et
F2 code> pourrait également être défini de manière dynamique):
eval code>, car cela ouvre un trou de sécurité pour le code d'entrée d'utilisateur malveillant. P> p>
J'ai besoin que de remplacer la substitution. L'évaluation sera effectuée avec un autre programme (simulateur)
Je pense que vous voulez utiliser quelque chose comme Voir un exemple contenant le code de base dont vous avez besoin ici: p>
pybison code> qui est un générateur d'analyseur. P>
Écrire un analyseur semble être trop sucré lorsque la grammaire est un sous-ensemble de Python
Connaissez-vous les variables à l'avance?
Je recommande d'utiliser Sydy! P>
Prenons par exemple les éléments suivants: P>
import sympy a,b,x,y = sympy.symbols('a b x y') f1 = sympy.Function('f1') f2 = sympy.Function('f2') readString = "a+b+f1(f2(x,y),x)" z = eval(readString)
Généralement intéressant. Mais dans mon cas, je ne sais pas les variables à l'avance.
Voici un exemple de travail minimal ( Un peu plus que la fonctionnalité de l'exemple donné est effectuée: p> USAGE: P> +, -, *, /, ** code> des opérations binaires et uniques et des appels de fonction mises en œuvre). La priorité des opérations est définie avec des parenthèses.
((-(a+b)+(((sin((+x+y))+(z**2))*4)/365.12))-h)
Semble fonctionner bien. Actuellement, le seul problème mineur est des parenthèses redondantes, mais ça va toujours bien. Merci.
Pour supprimer les parenthèses redondantes, vous devez tenir compte de la priorité de l'opérateur. Je préférais ne pas faire. L'expression est corenconnée même si cela pourrait être simplifié
(en utilisant Le code ci-dessous convertit une chaîne donnée en une nouvelle chaîne après avoir combiné les fonctions données. C'est hâtif et mal documenté, mais avertissement! strong> p> contient update: strong> p> symboly code> comme Adrianx suggéré, avec un certain code supplémentaire.)
EXEC code>
eval code>, le code malveillant pourrait probablement avoir une Effectué, si l'entrée est fournie par des utilisateurs externes. p>
J'ai essayé initial_str = 'A + myF1 (myF2 (a, b), y)' function_names = {'myf1 (x, y)': 'croix (x, y)', 'myf2 (a, b) ':' valeur (A, b) '} code> mais a eu une erreur
@ALEX Le problème est que valeur code> et
cross code> n'existe pas dans la sympty. Je l'ai mis en mesure de reconnaître toutes les fonctions de sympty (
SIN, COT, SQRT CODE>, etc.). Peut-être ont-ils un nom différent. Je suppose que
cross code> est "Cross Product", correct? Quelle est la valeur
code> cependant?
@Alex Il peut probablement être corrigé si je fais une dicte avec des noms personnalisés tels que Cross code> correspondant au nom équivalent dans Sydy. Mon mauvais pour les pauvres docstrings que j'ai utilisés. At-il fonctionné pour d'autres noms de fonction?
Comme je l'ai écrit, une fois les résultats de traduction seront utilisés dans un autre programme, le programme est un simulateur analogique. Donc, la fonction croisée est la fonction de croisement de deux signaux analogiques et la fonction de valeur donne une valeur Y du signal donné à X. Ce dont j'ai besoin est une traduction générale de tout nom de fonction arbitraire sur tout autre nom de fonction arbitraire. Des noms de toutes les fonctions connues à l'avance
Presque. Mais la réponse acceptée ajoute beaucoup de parenthèses redondantes et une nouvelle fonction nécessite une virgule comme séparateur entre les arguments lorsque j'ai vraiment besoin d'espace comme séparateur.
@Alex Bien que vous ayez déjà accepté une réponse différente de celle de la mienne, et rien pour moi de gagner, je vais essayer de vous aider. Cependant, essayez d'être plus précis. J'ai vraiment besoin d'espace comme séparateur i> - c'est une nouvelle exigence que vous n'avez pas mentionnée. Donne un exemple.
Merci pour vos efforts. Je pense que ce sera utile non seulement pour moi, mais aussi pour d'autres personnes ayant le même problème. Je vois déjà quatre ajoutés cette question aux favoris. Je pense que je ne m'avais pas bien expliqué sur l'espace comme séparateur. Le problème est que je voudrais généralement remplacer la fonction par fonction comme je voudrais remplacer C (x, y) par croix (x y a b c). Donc, séparateur de virgule, bon pour la fonction source, mais dans la fonction de destination, j'ai besoin d'espace comme séparateur.
Car il est possible de remplacer toutes les virgules par des espaces après la substitution. Mais ce sera bien si je serai capable de spécifier la fonction de destination avec des espaces à l'origine. Pour une question acceptée, j'ai besoin d'écrire la fonction de destination comme croix (x, y, a, b, c)
Est-ce que tu ayé mon nouveau code? Fonctionne-t-il comme prévu? Des bugs?
La substitution complète est assez délicate. Voici ma tentative de le faire. Ici, nous pouvons avoir des expressions en ligne avec succès,
Mais pas dans tous les scénarios. Ce code fonctionne uniquement sur AST, fait par le module Nous Définissez quelques aides: P> ast code>. Et utilise
codeGen code> pour le ramener au code. Le stringification de AST et de modification ast en général est couvert dans d'autres Q / A: "Analyser un fichier .PY, lisez l'AST, modifiez-le, puis écrivez le code source modifié" .
f1 first, unique variable names
expand call to f1(u, v) with arguments f2(x, y), x
substitute
name u for f2(x, y)
name v for x
in sin((u + v))
expand call to f2(i, j) with arguments x, y
substitute
name i for x
name j for y
in ((i + j) ^ 2)
((a + b) + sin((((x + y) ^ 2) + x)))
---
f1 first
expand call to f1(x, y) with arguments f2(x, y), x
substitute
name y for x
name x for f2(x, y)
in sin((x + y))
expand call to f2(x, y) with arguments x, y
substitute
name y for y
name x for x
in ((x + y) ^ 2)
((a + b) + sin((((x + y) ^ 2) + x)))
---
f2 first
expand call to f1(x, y) with arguments f1(x, x), y
expand call to f1(x, y) with arguments x, x
substitute
name y for x
name x for x
in (x + y)
substitute
name y for y
name x for (x + x)
in (x + x)
((x + x) + ((x + x) + x))
---
fact
expand call to fact(n) with arguments n
substitute
name n for n
in n if (n == 0) else (n * fact((n - 1)))
expand call to fact(n) with arguments (n - 1)
substitute
name n for (n - 1)
in n if (n == 0) else (n * fact((n - 1)))
expand call to fact(n) with arguments ((n - 1) - 1)
substitute
name n for ((n - 1) - 1)
in n if (n == 0) else (n * fact((n - 1)))
n if (n == 0) else (n * (n - 1) if ((n - 1) == 0) else ((n - 1) * ((n - 1) - 1) if (((n - 1) - 1) == 0) else (((n - 1) - 1) * fact((((n - 1) - 1) - 1)))))
On dirait que le projet de CodeGen est homéancial et a des bugs critiques pour l'utilisation (pas de parenthèse autour de binop, donc aucune priorité d'exploitation) Le projet principal a cette demande en attente en attente d'attente github.com/andreif/codegen/pull/4/commits Donc, si quelqu'un veut l'utiliser, il serait préférable d'utiliser github.com/jbremer/codegen
Afin de reconstruire votre chaîne, vous devez utiliser Traversal LVR sur l'AST donné.
Pourquoi ne pas recueillir la chaîne?
@Maher c'est exactement la question. Comment puis-je effectuer Traversal LVR. J'ai besoin d'un exemple.
@Styvane Si je vais simplifier la corde, je pense que je serai incapable de travailler avec des fonctions imbriquées?
Hors de curiosité: essayez-vous de le faire pour une sorte d'algorithme évolutif?
@Alex Connaissez-vous chaque séquence de texte possible dans votre chaîne?
@ inspectorg4dget n ° N ° voulue simplement faire une automatisation pour la génération des mesures.
Êtes-vous ouvert à la représentation de vos fonctions dans un autre format que comme chaîne?
@Styvane Je connais toutes les fonctions possibles et toutes les opérations mathématiques mathématiques (+ - * /), mais elles peuvent venir dans n'importe quelle séquence et les équations peuvent être utilisées comme arguments de fonctions. De cause maintenant j'ai la mise en œuvre de la fonction singulaire. C'est simple. Je suppose que je trouverai la voie à traiter avec plusieurs fonctions sans fonctions imbriquées. Mais j'aimerais trouver une approche universelle qui fonctionnera sans limitations.
@ inspectorg4dget je pense que non. Les humains doivent être capables d'écrire des équations :) Je suppose qu'ils ne voudront pas créer quelque chose qui n'est pas une chaîne :)
N'avez pas le temps d'écrire la solution en ce moment, mais jetez un coup d'œil à la fonction
parse code> ICI . Il y a quelque chose là-bas que vous pouvez étendre à votre but
Je suppose que les formules ne sont pas très grandes (~~ 1 ligne)? Pourquoi ne pouvez-vous pas faire cela de manière triviale avec une substitution de Regexp (peut-être nidifier)? Si vous ne pouvez pas, je peux vous montrer une réponse non python qui peut faire des remplaçants arbitraires, y compris les remplaçants «imbriqués», tous basés sur des asts.
Que pense votre programme externe des
^ code> et
** code> opérateurs?
@Irabaxter Il est difficile de traiter des fonctions à l'intérieur des fonctions et de plusieurs niveaux de parenthèses avec REGEXP. La programmation n'est également pas mon travail principal et j'ai besoin d'une solution relativement simple (pas de consommation de temps).
@ERIC ^ est la fonction xor ** est un exposant
Vous décidez-vous si le résultat a des parenthèses redondantes? C'est-à-dire que si vous donnez la fonction
a + b * x code>, étiez-vous si vous avez récupéré
(A + (b * x)) code> (indépendant de la substitution de la fonction)? Ou en d'autres termes, l'expression convertie est-elle destinée à un traitement ultérieur ou à l'affichage des êtres humains?
Et une autre question: vos fonctions ont-elles des variables gratuites?
@ici l'expression convertie destinée à un traitement ultérieur, mais également affichée aux êtres humains. Mais les parenthèses redondantes peuvent être ok.
@ici ce que tu veux dire par des variables libres?