0

The client passed me a parameter str = "${param0},${param1}". I want to replace ${param0} ${param1} with the value I queried from the database.

such as

//str = "${param0},${param1}"
//str = "${param0},${param1}, ${param2}"
//...
public String format(String str) {

    String param0 = repository.query0();
    //expect
    str = "param0,${param1}";

    String param1 = repository.query1();
    //expect
    str = "param0,param1,${param2}";

    return str;
}

I know that java.lang.String#replace can solve the problem. But the parameter str is indefinite. It could also be str = "${param0}, ${param1}, ${param2}" or more. Is there any way to satisfy my request?

dai
  • 1,025
  • 2
  • 13
  • 33

2 Answers2

2

If you can be confident that it will always be in the format of ${paramX} then you can do the following:

String str = ...;
for (int i = 0; i < results.length; i++)
{
    str = str.replace("${param" + i + "}", results[i]);
}

Replace the contents of the for loop and the resutls[i] portion to be however you access the data returned from your query.

If you instead can't dependent on ${paramX} being in sequential order, you can use a more hacky solution by using the following code:

// create a new StringBuilder to reduce concatentation
StringBuilder result = new StringBuilder();

// our warped string input
String str = "${param0}, ${param12}${param1234}${param2}";

// split it anywhere that is formatted with ${paramXXXX}
String[] parts = str.split("\\$\\{param[0-9]{1,}\\}");

// loop through the pieces
for (int i = 0; i < parts.length; i++)
{
    // get the parts of the string that are not ${paramXXXX}
    result.append(parts[i]);

    // the results from the query.
    result.append(queryResults[i]); // Replace with the proper way to read your query results
}

The above code should work no matter the input, as long as there are the same number of query results as there are ${paramXXXX} pieces in the input string.

Be sure to replace the code followed by // Replace with ... with the code to read your query results.

Michael Ziluck
  • 599
  • 6
  • 19
  • The replacement value is queried from the database. – dai Jun 26 '18 at 12:24
  • @Frank.Dai this change nothing, the answer is correct. It assumes you made something like `String[] results = query.getResultArray();` – vincrichaud Jun 26 '18 at 12:25
  • what if **${param0},${param10}** – dai Jun 26 '18 at 12:29
  • In that case, as long as you have 11 results (0 through 10 = 11) it would work fine. However, if you have to account for there actually only being two values and the number following `${paramX}` is actually arbitrary, you are going to need to have more logic to handle that. I will write one up now :) – Michael Ziluck Jun 26 '18 at 12:34
  • @MichaelZiluck I think the real problem (but really badly explained) is that str is like your second example. And from it OP need to read the number (first 0), query the database for value (value at index 0) then replace the string by the value. And do same for the second one : read value 12, query database for value12, replace string ${param12} by the value gueried. et... – vincrichaud Jun 26 '18 at 12:46
  • Oh! Is that the case Frank.Dai? If so, I can write up another example again. – Michael Ziluck Jun 26 '18 at 12:57
  • @Frank.Dai could you confirm I understand well your problem ? So Micheal can update his answer – vincrichaud Jun 26 '18 at 13:17
  • String.replaceAll(...) uses a regular expression to select the sections of the string to replace. I think String.replace(...) is more appropriate in this case, and will replace all occurrences. – Jamie Jun 26 '18 at 13:33
  • @Jamie, fixed that! – Michael Ziluck Jun 26 '18 at 13:36
1

Here is an approach using matcher:

String str = "${param0},${param1}, ${param2}";
System.out.println("Matching: "+str);
Pattern regex = Pattern.compile("\\$\\{(\\w+)\\}");
Matcher matcher = regex.matcher(str);
while (matcher.find()){
  System.out.println("found: "+matcher.group());
  str = matcher.replaceFirst("results");
  matcher = regex.matcher(str);
}
System.out.println("Result: "+str);

This is not very efficient, but easy to use. If you have gigabyte-scale computations, consider looping over your input string and compare characters manually.

Update:

Here is a better approach. More efficient and not susceptible for endless loop if results contain the pattern.

String str = "[${param0},${param1}, ${param2}]";
System.out.println("Matching: " + str);
final Pattern regex = Pattern.compile("\\$\\{(\\w+)\\}"); 
final Matcher matcher = regex.matcher(str);
final StringBuilder sb = new StringBuilder(str.length());
int prevMatch = 0;
while (matcher.find()) {
  System.out.println("found: " + matcher.group());
  sb.append(str.substring(prevMatch, matcher.start()));
  sb.append("results");
  prevMatch = matcher.end();
}
sb.append(str.substring(prevMatch, str.length()));
System.out.println("Result: " + sb.toString());
Imaskar
  • 2,773
  • 24
  • 35