1

I have a String that is coming from an API or stored in my database, and I want to replace all tags with my tags at runtime. Is there any efficient way to achieve this?

Using if else is not efficient, since my model has more than 100 fields.

String rawText= "Hello %name% !, Nice to meet you! Your age is %age%."

I want replace all %____% text with my value stored in my Model.

class Person{
     private String name;
     private String age;

     getter...
     setter....
}
5
  • what have you tried? ever heard of concatenation? Commented Dec 27, 2017 at 7:20
  • What version of Java are you using? Commented Dec 27, 2017 at 7:22
  • Are you using Jackson or Gson by any chance? Commented Dec 27, 2017 at 7:23
  • Jaction or GSON convert json to java object but its not json. also I am not trying to convert json to java object. finding pattern(%age%) from text is not an issue but getting age from model where public method is getAge(). Commented Dec 27, 2017 at 7:26
  • I understand what you're trying to do. Please answer the question(s). Commented Dec 27, 2017 at 7:26

4 Answers 4

2

You can use reflection to get the field values by name:

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String replaceTags(String rawText) {
        Matcher m = Pattern.compile("%(.+?)%").matcher(rawText);
        boolean result = m.find();
        if (result) {
            StringBuffer sb = new StringBuffer();
            do {
                m.appendReplacement(sb, Matcher.quoteReplacement(getField(m.group(1))));
                result = m.find();
            } while (result);
            m.appendTail(sb);
            return sb.toString();
        }
        return rawText.toString();
    }

    private String getField(String name) {
        try {
            return String.valueOf(this.getClass().getDeclaredField(name).get(this));
        } catch (Exception e) {
            throw new IllegalArgumentException("could not read value for field: " + name);
        }
    }
}

Ideone Demo

If you're on Java 9, you can simplify replaceTags() with a replacement function:

public String replaceTags(String rawText) {
    return Pattern.compile("%(.+?)%").matcher(rawText)
            .replaceAll(r -> Matcher.quoteReplacement(getField(r.group(1))));
}

If you have a JSON serialization library like Jackson, you can use it to handle the reflection automatically and build a map of values by field name:

Map<String, Object> fieldValues = new ObjectMapper()
        .convertValue(this, new TypeReference<Map<String, Object>>() {});
Sign up to request clarification or add additional context in comments.

1 Comment

I like this solution and I think using "%(\w+)%" in regular expression can handle empty %%
2

Using Reflection You can do it with few lines of code :

import java.lang.reflect.Field;
public class Main {
public static void main(String arg[]) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
    String rawText= "Hello %name% !, Nice to meet you! Your age is %age%.";
    Field[] fields = Person.class.getFields();

    Person person = new Person("TestName", "TestAge");

    for(Field  field: fields) {
        rawText = rawText.replace("%"+field.getName()+"%", (String)field.get(person));
    }
}
}

Just make the fields public in Person class.

5 Comments

This solution doesn't use regex. Use String.replace() instead.
@Tom It uses a method that expects regex, but the value passed in is plaintext and may in fact be invalid regex.
What I did can also be done without regex, plaintext can also be treated as regex. Yeah it can be invalid, but as per java naming conventions[camel case] it should not be invalid.
@shmosel I just answered with the relevance to the question, I am not seeing any field will be having base64 string, It's just some name, age or whatever a person have as property.
plaintext can also be treated as regex. Not as a rule. a$ is a valid field name. See what happens if you try replacing it as regex.
1

you can use replaceAll

    String rawText= "Hello %name% !, Nice to meet you! Your age is %age%.";
    rawText = rawText.replaceAll("%name%", "new name");
    rawText = rawText.replaceAll("%age%", "new age");

where the new name and new age can come from your model.

2 Comments

Use replace() unless you need regex.
true replaceAll for regex. here replace should do.
0

I don't see any reason why regular string concatenation would not be sufficient here. Just define a helper method inside Person which builds the output string using the properties of a given person:

public class Person {
    // ...
    public String getGreeting() {
        StringBuilder sb = new StringBuilder("");
        sb.append("Hello ").append(name).append(", nice to meet you!  Your age is ");
        sb.append(age).append(".");

        return sb.toString();
    }
}

2 Comments

thanks for answer, but my use case don't meet the answer because i don't know what will be the raw text , it could be any text with tags like ..%age%
@NandanSingh OK...I will leave this post here in case it might be useful to someone else.

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.