programing

속도 템플릿과 유사한 자바의 문자열 대체

nasanasas 2020. 10. 6. 08:17
반응형

속도 템플릿과 유사한 자바의 문자열 대체


String텍스트로 객체를 전달할 수있는 Java에 대체 메커니즘 이 있습니까? 문자열이 발생하면이를 대체합니다.
예를 들어 텍스트는 다음과 같습니다.

Hello ${user.name},
    Welcome to ${site.name}. 

내가 가진 개체는 "user""site"입니다. 내부 ${}주어진 문자열을 객체의 동등한 값 으로 바꾸고 싶습니다 . 이것은 속도 템플릿에서 객체를 교체하는 것과 같습니다.


java.text.MessageFormat클래스를 살펴보면 MessageFormat은 개체 집합을 가져 와서 형식을 지정한 다음 형식이 지정된 문자열을 적절한 위치의 패턴에 삽입합니다.

Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);

StrSubstitutorApache Commons Lang에서 사용합니다 .

https://commons.apache.org/proper/commons-lang/

그것은 당신을 위해 할 것입니다 (그리고 오픈 소스 ...)

 Map<String, String> valuesMap = new HashMap<String, String>();
 valuesMap.put("animal", "quick brown fox");
 valuesMap.put("target", "lazy dog");
 String templateString = "The ${animal} jumped over the ${target}.";
 StrSubstitutor sub = new StrSubstitutor(valuesMap);
 String resolvedString = sub.replace(templateString);

나는 이것의 작은 테스트 구현을 함께 던졌다. 기본 아이디어는 format형식 문자열, 객체 맵 및 로컬에있는 이름 을 호출 하고 전달하는 것입니다.

다음의 출력은 다음과 같습니다.

내 개 이름은 fido이고 Jane Doe는 그를 소유합니다.

public class StringFormatter {

    private static final String fieldStart = "\\$\\{";
    private static final String fieldEnd = "\\}";

    private static final String regex = fieldStart + "([^}]+)" + fieldEnd;
    private static final Pattern pattern = Pattern.compile(regex);

    public static String format(String format, Map<String, Object> objects) {
        Matcher m = pattern.matcher(format);
        String result = format;
        while (m.find()) {
            String[] found = m.group(1).split("\\.");
            Object o = objects.get(found[0]);
            Field f = o.getClass().getField(found[1]);
            String newVal = f.get(o).toString();
            result = result.replaceFirst(regex, newVal);
        }
        return result;
    }

    static class Dog {
        public String name;
        public String owner;
        public String gender;
    }

    public static void main(String[] args) {
        Dog d = new Dog();
        d.name = "fido";
        d.owner = "Jane Doe";
        d.gender = "him";
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("d", d);
        System.out.println(
           StringFormatter.format(
                "My dog is named ${d.name}, and ${d.owner} owns ${d.gender}.", 
                map));
    }
}

참고 : 처리되지 않은 예외로 인해 컴파일되지 않습니다. 그러나 코드를 훨씬 쉽게 읽을 수 있습니다.

또한 코드에서 직접 맵을 구성해야한다는 점이 마음에 들지 않지만 프로그래밍 방식으로 지역 변수의 이름을 얻는 방법을 모릅니다. 이를 수행하는 가장 좋은 방법은 객체를 생성하자마자지도에 객체를 배치하는 것입니다.

다음 예제는 예제에서 원하는 결과를 생성합니다.

public static void main(String[] args) {
    Map<String, Object> map = new HashMap<String, Object>();
    Site site = new Site();
    map.put("site", site);
    site.name = "StackOverflow.com";
    User user = new User();
    map.put("user", user);
    user.name = "jjnguy";
    System.out.println(
         format("Hello ${user.name},\n\tWelcome to ${site.name}. ", map));
}

나는 또한 Velocity가 무엇인지 모른다는 것을 언급해야 하므로이 답변이 관련이 있기를 바랍니다.


My preferred way is String.format() because its a oneliner and doesn't require third party libraries:

String result = String.format("Hello! My name is %s, I'm %s.", NameVariable, AgeVariable); 

I use this very often in exception messages, like:

throw new Exception(String.format("Unable to login with email: %s", email));

Hint: You can put in as many variables as you like because format() uses Varargs


Here's an outline of how you could go about doing this. It should be relatively straightforward to implement it as actual code.

  1. Create a map of all the objects that will be referenced in the template.
  2. Use a regular expression to find variable references in the template and replace them with their values (see step 3). The Matcher class will come in handy for find-and-replace.
  3. Split the variable name at the dot. user.name would become user and name. Look up user in your map to get the object and use reflection to obtain the value of name from the object. Assuming your objects have standard getters, you will look for a method getName and invoke it.

There are a couple of Expression Language implementations out there that does this for you, could be preferable to using your own implementation as or if your requirments grow, see for example JUEL and MVEL

I like and have successfully used MVEL in at least one project.

Also see the Stackflow post JSTL/JSP EL (Expression Language) in a non JSP (standalone) context


There is nothing out of the box that is comparable to velocity since velocity was written to solve exactly that problem. The closest thing you can try is looking into the Formatter

http://cupi2.uniandes.edu.co/site/images/recursos/javadoc/j2se/1.5.0/docs/api/java/util/Formatter.html

However the formatter as far as I know was created to provide C like formatting options in Java so it may not scratch exactly your itch but you are welcome to try :).


I use GroovyShell in java to parse template with Groovy GString:

Binding binding = new Binding();
GroovyShell gs = new GroovyShell(binding);
// this JSONObject can also be replaced by any Java Object
JSONObject obj = new JSONObject();
obj.put("key", "value");
binding.setProperty("obj", obj)
String str = "${obj.key}";
String exp = String.format("\"%s\".toString()", str);
String res = (String) gs.evaluate(exp);
// value
System.out.println(str);

참고URL : https://stackoverflow.com/questions/3655424/string-replacement-in-java-similar-to-a-velocity-template

반응형