2010-05-16 6 views
2

Existe-t-il un moyen de résoudre les expressions mathématiques dans les chaînes en javascript? Par exemple, supposons que je veuille produire la chaîne "Tom a 2 pommes, Lucy a 3 pommes, ensemble ils ont 5 pommes" mais je veux pouvoir les substituer dans les variables. Je peux le faire avec un remplacement de chaîne:Chaîne Javascript remplacer par des calculs

string = "Tom has X apples, Lucy has Y apples. Together they have Z apples"; 
string2 = string.replace(/X/, '2').replace(/Y/, '3').replace(/Z/, '5'); 

Cependant, il serait mieux si, au lieu d'avoir une variable Z, je pourrais utiliser X + Y. Maintenant, je pourrais aussi faire une chaîne de remplacement pour X + Y et la remplacer par la valeur correcte, mais cela deviendrait désordonné en essayant de gérer tous les calculs possibles dans la chaîne que je pourrais vouloir faire. Je suppose que je suis à la recherche d'un moyen pour y parvenir:

string = "Something [X], something [Y]. Something [(X+Y^2)/(5*X)]"; 

Et pour les [___] parties à comprendre comme des expressions à résoudre avant de remplacer de nouveau dans la chaîne.

Merci pour votre aide.

+0

Vous êtes un perdant avec l'opérateur "power". En javascript, cela signifie XOR. – Eric

+0

@Eric: C'est un très bon point. –

Répondre

4

Il n'y a pas directe, moyen intégré (bien, d'accord, peut-être il y a   — voir ci-dessous), mais si vous utilisez la fonction de rappel de la fonction replace, où le remplacement peut être une fonction plutôt qu'une chaîne (la valeur de retour est ce qui est substitué dans), vous pouvez l'appliquer assez facilement. Par exemple, supposons que vous utilisiez la notation Ruby #{xyz} pour vos espaces réservés. Par exemple, supposons que vous utilisiez la notation Ruby #{xyz}. Ce code boucle à travers ceux-ci:

var mappings, str; 

str = "One #{X} three #{Y} five"; 
mappings = { 
    "X": 2, 
    "Y": 4 
}; 
str = str.replace(/\#\{([^#]+)\}/g, function(match, key) { 
    var result; 

    result = mappings[key]; 
    /* ...processing here */ 
    return result; 
}); 

La chaîne résultante est One 2 three 4 five, parce que #{X} et #{Y} ont été remplacés par recherche. Vous pouvez regarder la clé et voir si c'est une expression et doit être évaluée plutôt que simplement recherchée. Cette évaluation est là

Maintenant, le vrai travail vient en vous votre pouvez utiliserwith et eval pour obtenir le soutien d'expression. changer la ligne result = mapping[key]; ci-dessus à ceci:

with (mappings) { 
     result = eval(key); 
    } 

Si vous nourrissez la chaîne "One #{X} three #{Y} five #{X + Y * 2}" dans ce, le résultat est One 2 three 4 five 10   — parce 2 + 4 * 2 = 10.

Cela fonctionne parce que with sticks l'objet donné au-dessus de la chaîne de portée, de sorte qu'il est la première chose vérifiée lors de la résolution d'une référence non qualifiée (comme), et eval exécute le code Javascript   — et peut donc évaluer les expressions   — et le fait magiquement dans le cadre dans lequel il est appelé. Mais méfiez-vous; Comme Eric l'a souligné, tous les opérateurs ne sont pas les mêmes dans différentes formes d'expression, et en particulier Javascript interprète ^ pour signifier «bit au format XOR», pas «au pouvoir de». (Il n'a pas un opérateur d'exposant, vous devez utiliser Math.pow.)

Mais vous devez faire très attention à ce genre de chose, à la fois with et eval (chacun à leur manière) peut être problématique.Mais les principaux problèmes avec with sont qu'il est difficile de dire d'où vient quelque chose ou où cela ira si vous faites une tâche, ce que vous n'êtes pas; et les principaux problèmes avec eval viennent de l'utiliser pour interpréter des chaînes que vous ne contrôlez pas. Tant que vous gardez en place des garanties et sont conscients des problèmes ...

ébullition en une fonction:

function evaluate(str, mappings) { 
    return str.replace(/\#\{([^#]+)\}/g, function(match, key) { 
     var result; 

     with (mappings) { 
      result = eval(key); 
     } 

     return result; 
    }); 
} 
alert(evaluate(
    "The expression '(#{X} + #{Y}) * 2' equals '#{(X + Y) * 2}'", 
    {"X": 2, "Y": 4} 
)); // alerts "The expression '(2 + 4) * 2' equals '12'" 
alert(evaluate(
    "The expression '(#{X} + #{Y}) * 2' equals '#{(X + Y) * 2}'", 
    {"X": 6, "Y": 3} 
)); // alerts "The expression '(6 + 3) * 2' equals '18'" 
+1

C'est très bien - beaucoup plus court que ce à quoi je m'attendais. +1 – Kobi

+0

Nice de W3Schools de ne pas documenter cette fonctionnalité particulière de 'remplacer' ... http://www.w3schools.com/jsref/jsref_replace.asp – Eric

+0

@Eric: Oui, w3schools est pratique, mais pas fiable, si vous suis moi. MDC (https://developer.mozilla.org/En) est généralement assez bon (ils ont des problèmes de système pour le moment). En général, je recherche simplement sur le nom de la fonction plus "mdc" ou "msdn" (selon que je dois vérifier les caprices d'IE). –

1

La seule façon que je peux penser pour y parvenir serait un moteur de template tel que jTemplates. Voir aussi les réponses à this SO question.

1

question Nice:

function substitutestring(str,vals) 
{ 
    var regex = /\[[^\]]*\]/gi; 
    var matches = str.match(regex); 
    var processed = []; 

    for(var i = 0; i<matches.length; i++) 
    { 
     var match = matches[i]; 
     processed[match] = match.slice(1,-1); 

     for(j in vals) 
     { 
      processed[match] = processed[match].replace(j,vals[j]); 
     } 

     processed[match] = eval("("+processed[match]+")"); 
    } 

    for(var original in processed) 
    { 
     str = str.replace(original,processed[original]); 
    } 
    return str; 
} 

document.write(
    substitutestring(
     "[x] + [y] = [x+y]", 
     {"x": 1, "y": 2} 
    ) 
); 
0

En ES6 vous pouvez maintenant utiliser template strings:

var X = 2, Y = 3; string = Tom has ${X} apples, Lucy has ${Y} apples. Together they have ${X+Y} apples;