4

I'm currently building a config file that will replace a given string with multiple variables, I'm having a hard time explaining it so perhaps it would be best to show you what I mean:

The following method will be used with the String: Hello ~ and welcome to ~!

private static String REPLACE_CHAR = "~";

public static String parse(String key, String... inputs) {
    int cache = matchCache.get(key, -1);
    String value = customConfig.getString(key);
    if (cache == -1) {
        cache = StringUtils.countMatches(value, REPLACE_CHAR);
        matchCache.put(key, cache);
    }
    for (int i = 0; i < cache; i++) {
        value = value.replaceFirst(REPLACE_CHAR, inputs[i]);
    }
    return value;
}

what would be the fastest way to replace ~ with the first input, then move to the second ~ and so on...

Now the main reason I haven't used someone else's code: Ideally I'd like to create a List of different replaceable characters which will in turn replace the variable automatically, so in this same code I'm able to give it no inputs but it will check the List for replaceable characters and perform a method such as getYourName() This list does not need to be checked every time so a pattern may still be compiled?

I'm doing this to learn as much as for efficiency, I lack in ability when it comes to regex!

2
  • What's wrong with what you have? Do you get an error? Or are you just looking for a more efficient way? Commented Nov 12, 2012 at 22:03
  • 1
    That's it, efficiency is what I'm after! Heck this works, I'm just looking at it thinking to myself.. I know there's a better, cleaner and more customize-able way of doing this! Commented Nov 12, 2012 at 22:05

1 Answer 1

2

If you're looking for efficiency you can instantiate a Matcher using a regular expression, and then use the find() method to find occurrences, appending a replacement for each occurrence into a StringBuffer.

private Matcher matcher = Pattern.compile("([~])").matcher("");

public String parse(String key, String... inputs) {
    String value = customConfig.getString(key);
    matcher.reset(value);
    StringBuffer sb = new StringBuffer();
    int i = 0;
    while (matcher.find()) {
      String text = matcher.group(1);
      matcher.appendReplacement(sb, inputs[i++]);
    }
    matcher.appendTail(sb);
    return sb.toString();
}

System.out.println(parse("foo", "T F C", "James Bond"));
// prints "Hello T F C, my name is James Bond" 
// if customConfig.getString("foo") returns "Hello ~, my name is ~"

This way you avoid the finding from beginning of the string during each loop involved in String.replaceFirst. But you can still cache the number of ~ found if you want to verify that the length of input[] does equal to it.

The sample above does ignore the fact that the correct number of entries are stored in inputs[].

Runnable sample can be found here: http://ideone.com/QfE03a

Sign up to request clarification or add additional context in comments.

3 Comments

Damn, I so have to learn Regex! :D How taxing is instantiating a new Matcher for each different match, say If I wanted a matcher for %p or another random variable aswell as ~ then matching and replacing anything with that? Sorry, You've already done above and beyond! Thankyou so much! :)
You can instantiate one Matcher for each different Pattern and call Matcher.reset(String) to init the matcher for the given String. Calling reset on a Matcher is less taxing than compiling a Pattern and instantiate a new Matcher from it each time.
Love it! Thankyou Alex, Exactly what I was looking for!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.