0

I have some strings with equations in the following format ((a+b)/(c+(d*e))).

I also have a text file that contains the names of each variable, e.g.:

a velocity
b distance
c time

etc...

What would be the best way for me to write code so that it plugs in velocity everywhere a occurs, and distance for b, and so on?

1
  • See this and this Commented Jan 28, 2014 at 23:02

4 Answers 4

4

Don't use String#replaceAll in this case if there is slight chance part you will replace your string contains substring that you will want to replace later, like "distance" contains a and if you will want to replace a later with "velocity" you will end up with "disvelocityance".

It can be same problem as if you would like to replace A with B and B with A. For this kind of text manipulation you can use appendReplacement and appendTail from Matcher class. Here is example

String input = "((a+b)/(c+(d*e)))";

Map<String, String> replacementsMap = new HashMap<>();
replacementsMap.put("a", "velocity");
replacementsMap.put("b", "distance");
replacementsMap.put("c", "time");

StringBuffer sb = new StringBuffer();
Pattern p = Pattern.compile("\\b(a|b|c)\\b");
Matcher m = p.matcher(input);
while (m.find())
    m.appendReplacement(sb, replacementsMap.get(m.group()));
m.appendTail(sb);

System.out.println(sb);

Output:

((velocity+distance)/(time+(d*e)))

This code will try to find each occurrence of a or b or c which isn't part of some word (it doesn't have any character before or after it - done with help of \b which represents word boundaries). appendReplacement is method which will append to StringBuffer text from last match (or from beginning if it is first match) but will replace found match with new word (I get replacement from Map). appendTail will put to StringBuilder text after last match.


Also to make this code more dynamic, regex should be generated automatically based on keys used in Map. You can use this code to do it

StringBuilder regexBuilder = new StringBuilder("\\b(");
for (String word:replacementsMap.keySet())
    regexBuilder.append(Pattern.quote(word)).append('|');
regexBuilder.deleteCharAt(regexBuilder.length()-1);//lets remove last "|"
regexBuilder.append(")\\b");
String regex = regexBuilder.toString();
Sign up to request clarification or add additional context in comments.

4 Comments

"\\b" boundary match as you already have in the pattern will only match on the exact word so replaceAll would work as well.
@bdrx Not exactly. replaceAll is not good approach for multiple replacement problem. 1) it iterates over string multiple times, 2) what if OP will want to change wor1 with word2 and word2 with word1?
@Pshemo For the case of multiple variable replacement such as wor1 = word2 and word2 needing to be replaced with word1 replaceAll is not a good approach. However, for the problem domain where the original variables are in a non-intersecting set (as described in the problem) with the replacement variables the replaceAll solution is fine.
@bdrx True for this particular case, but we don't know what real values OP will want to replace. That is why I suggested safer variant.
2

I'd make a hashMap mapping the variable names to the descriptions, then iterate through all the characters in the string and replace each occurrance of a recognised key with it's mapping. I would use a StringBuilder to build up the new string.

Comments

0

Using a hashmap and iterating over the string as A Boschman suggested is one good solution.

Another solution would be to do what others have suggested and do a .replaceAll(); however, you would want to use a regular expression to specify that only the words matching the whole variable name and not a substring are replaced. A regex using word boundary '\b' matching will provide this solution.

String variable = "a";
String newVariable = "velocity";
str.replaceAll("\\b" + variable + "\\b", newVariable);

See http://docs.oracle.com/javase/tutorial/essential/regex/bounds.html

4 Comments

But would it not find c in "velocity"? It's the whole string c, not a substring. I'm not that familiar with regex, is why I'm asking.
No it would not find c in velocity. It only matches a string that is prefixed and followed by a word boundary. That is any character matching (\W) which is non word character (doesn't match \w)
Okay, I see. That would indeed work. However, if the input string might be of the format 'ab' instead of 'a*b', a common notation for muliplication in maths, it wouldn't work anymore.
@ABoschman true. replaceAll would only be a good solution for a simple problem domain where syntax would follow requirements such as those in java where all variables must be separated by whitespace or an operator
-2

For string str, use the replaceAll() function:

str = str.toUpperCase();  //Prevent substitutions of characters in the middle of a word
str = str.replaceAll("A", "velocity");
str = str.replaceAll("B", "distance");
//etc.

2 Comments

This is not safe approach. What if replacement will contain character that will can be used as replacement of another character? For instance if you change order and replace b first with distAnce and then replace a with velocity you will get disvelocityance.
of course this will depend on what the original string is. I'm assuming that the replacements are all lowercase.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.