Evan Cross
Evan Cross

Reputation: 31

Elegant way to do variable substitution in a java string

Pretty simple question and my brain is frozen today so I can't think of an elegant solution where I know one exists.

I have a formula which is passed to me in the form "A+B"

I also have a mapping of the formula variables to their "readable names".

Finally, I have a formula parser which will calculate the value of the formula, but only if its passed with the readable names for the variables.

For example, as an input I get

String formula = "A+B"
String readableA = "foovar1"
String readableB = "foovar2"

and I want my output to be "foovar1+foovar2"

The problem with a simple find and replace is that it can be easily be broken because we have no guarantees on what the 'readable' names are. Lets say I take my example again with different parameters

String formula = "A+B"
String readableA = "foovarBad1"
String readableB = "foovarAngry2"

If I do a simple find and replace in a loop, I'll end up replacing the capital A's and B's in the readable names I have already replaced.

This looks like an approximate solution but I don't have brackets around my variables

How to replace a set of tokens in a Java String?

Upvotes: 0

Views: 4927

Answers (5)

Lee Meador
Lee Meador

Reputation: 12985

Matching Only

If you don't have to evaluate the expression after doing the substitution, you might be able to use a regex. Something like (\b\p{Alpha}\p{Alnum}*\b)

or the java string "(\\b\\p{Alpha}\\p{Alnum}*\\b)"

Then use find() over and over to find all the variables and store their locations.

Finally, go through the locations and build up a new string from the old one with the variable bits replaced.

Not that It will not do much checking that the supplied expression is reasonable. For example, it wouldn't mind at all if you gave it )A 2 B( and would just replace the A and B (like )XXX 2 XXX(). I don't know if that matters.

This is similar to the link you supplied in your question except you need a different regular expression than they used. You can go to http://www.regexplanet.com/advanced/java/index.html to play with regular expressions and figure out one that will work. I used it with the one I suggested and it finds what it needs in A+B and A + (C* D ) just fine.

Parsing

You parse the expression using one of the available parser generators (Antlr or Sable or ...) or find an algebraic expression parser available as open source and use it. (You would have to search the web to find those, I haven't used one but suspect they exist.)

Then you use the parser to generate a parsed form of the expression, replace the variables and reconstitute the string form with the new variables.

This one might work better but the amount of effort depends on whether you can find existing code to use.

It also depends on whether you need to validate the expression is valid according to the normal rules. This method will not accept invalid expressions, most likely.

Upvotes: 0

AlexWien
AlexWien

Reputation: 28747

Your approach does not work fine that way
Formulas (mathematic Expressions) should be parsed into an expression structure (eg. expression tree).

Such that you have later Operand Nodes and Operator nodes.
Later this expression will be evaluated traversing the tree and considering the mathematical priority rules.

I recommend reading more on Expression parsing.

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533710

A simple way to do it is

String foumula = "A+B".replaceAll("\\bA\\b", readableA)
                      .replaceAll("\\bB\\b", readableB);

Upvotes: 0

LetMeSOThat4U
LetMeSOThat4U

Reputation: 6776

  1. A somewhat tedious solution would be to scan for all occurences of A and B and note their indexes in the string, and then use StringBuilder.replace(int start, int end, String str) method. (in naive form this would not be very efficient though, approaching smth like square complexity, or more precisely "number of variables" * "number of possible replacements")

  2. If you know all of your operators, you could do split on them (like on "+") and then replace individual "A" and "B" (you'd have to do trimming whitespace chars first of course) in an array or ArrayList.

Upvotes: 0

Ulises
Ulises

Reputation: 13429

That link you provided is an excellent source since matching using patterns is the way to go. The basic idea here is first get the tokens using a matcher. After this you will have Operators and Operands

Then, do the replacement individually on each Operand.

Finally, put them back together using the Operators.

Upvotes: 3

Related Questions