programing

Java String에서 토큰 세트를 바꾸려면 어떻게 해야 합니까?

randomtip 2022. 9. 4. 13:22
반응형

Java String에서 토큰 세트를 바꾸려면 어떻게 해야 합니까?

String은 ."Hello [Name] Please find attached [Invoice Number] which is due on [Due Date]".

이름, 청구서 번호, 기한에 대한 문자열 변수도 있습니다.템플릿의 토큰을 변수로 대체하는 가장 좋은 방법은 무엇입니까?

(변수에 토큰이 포함되어 있는 경우에는 치환하지 마십시오).


편집

@laginimaineb와 @alan-moore에 감사드리며, 저의 솔루션은 다음과 같습니다.

public static String replaceTokens(String text, 
                                   Map<String, String> replacements) {
    Pattern pattern = Pattern.compile("\\[(.+?)\\]");
    Matcher matcher = pattern.matcher(text);
    StringBuffer buffer = new StringBuffer();

    while (matcher.find()) {
        String replacement = replacements.get(matcher.group(1));
        if (replacement != null) {
            // matcher.appendReplacement(buffer, replacement);
            // see comment 
            matcher.appendReplacement(buffer, "");
            buffer.append(replacement);
        }
    }
    matcher.appendTail(buffer);
    return buffer.toString();
}

템플리트 엔진이나 그런 걸 쓸 필요는 없을 것 같아요다음과 같은 방법을 사용할 수 있습니다.

String template = "Hello %s Please find attached %s which is due on %s";

String message = String.format(template, name, invoiceNumber, dueDate);

가장 효율적인 방법은 매처를 사용하여 식을 지속적으로 검색하여 대체한 다음 텍스트를 문자열 빌더에 추가하는 것입니다.

Pattern pattern = Pattern.compile("\\[(.+?)\\]");
Matcher matcher = pattern.matcher(text);
HashMap<String,String> replacements = new HashMap<String,String>();
//populate the replacements map ...
StringBuilder builder = new StringBuilder();
int i = 0;
while (matcher.find()) {
    String replacement = replacements.get(matcher.group(1));
    builder.append(text.substring(i, matcher.start()));
    if (replacement == null)
        builder.append(matcher.group(0));
    else
        builder.append(replacement);
    i = matcher.end();
}
builder.append(text.substring(i, text.length()));
return builder.toString();

아쉽게도 편한 메서드 String입니다.위에서 언급한 포맷은 Java 1.5부터만 사용할 수 있습니다(요즘은 표준 사양이지만, 혹시 모르실 수도 있습니다.대신 플레이스홀더를 교체하기 위해 Java의 클래스 MessageFormat을 사용할 수도 있습니다.

'{number}' 형식의 자리 표시자를 지원하므로 "안녕하세요 {0} {2}에 만료되는 첨부된 {1}을(를) 찾으십시오."와 같은 메시지가 표시됩니다.이러한 문자열은 ResourceBundle을 사용하여 쉽게 외부화할 수 있습니다(예를 들어 여러 로케일을 사용한 현지화).MessageFormat 클래스의 static 'format' 메서드를 사용하여 교체합니다.

String msg = "Hello {0} Please find attached {1} which is due on {2}";
String[] values = {
  "John Doe", "invoice #123", "2009-06-30"
};
System.out.println(MessageFormat.format(msg, values));

Apache Velocity와 같은 템플릿 라이브러리를 사용해 볼 수 있습니다.

http://velocity.apache.org/

다음은 예를 제시하겠습니다.

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.io.StringWriter;

public class TemplateExample {
    public static void main(String args[]) throws Exception {
        Velocity.init();

        VelocityContext context = new VelocityContext();
        context.put("name", "Mark");
        context.put("invoiceNumber", "42123");
        context.put("dueDate", "June 6, 2009");

        String template = "Hello $name. Please find attached invoice" +
                          " $invoiceNumber which is due on $dueDate.";
        StringWriter writer = new StringWriter();
        Velocity.evaluate(context, writer, "TemplateName", template);

        System.out.println(writer);
    }
}

출력은 다음과 같습니다.

안녕하세요 마크.2009년 6월 6일까지의 청구서 42123을 첨부합니다.

복잡한 템플릿 교체에 템플릿 라이브러리를 사용할 수 있습니다.

FreeMarker는 매우 좋은 선택입니다.

http://freemarker.sourceforge.net/

그러나 간단한 작업을 위해 간단한 유틸리티 클래스가 도움이 됩니다.

org.apache.commons.lang3.text.StrSubstitutor

매우 강력하고 커스터마이즈 가능하며 사용하기 쉽습니다.

이 클래스는 텍스트를 하나 가져와서 그 안에 있는 모든 변수를 대체합니다.변수의 기본 정의는 ${variableName}입니다.접두사와 접미사는 생성자와 설정 메서드를 통해 변경할 수 있습니다.

변수 값은 일반적으로 맵에서 해결되지만 시스템 속성 또는 커스텀 변수 리졸버를 제공하여 해결할 수도 있습니다.

예를 들어 시스템 환경변수를 템플릿 문자열로 대체하려면 다음 코드를 사용합니다.

public class SysEnvSubstitutor {
    public static final String replace(final String source) {
        StrSubstitutor strSubstitutor = new StrSubstitutor(
                new StrLookup<Object>() {
                    @Override
                    public String lookup(final String key) {
                        return System.getenv(key);
                    }
                });
        return strSubstitutor.replace(source);
    }
}
System.out.println(MessageFormat.format("Hello {0}! You have {1} messages", "Join",10L));

출력: Hello Join!10개의 메시지가 있습니다.

String.format("Hello %s Please find attached %s which is due on %s", name, invoice, date)

바꾸려는 실제 데이터의 위치에 따라 달라집니다.다음과 같은 맵이 있을 수 있습니다.

Map<String, String> values = new HashMap<String, String>();

대체할 수 있는 모든 데이터가 포함되어 있습니다.그런 다음 맵에서 반복하여 String 내의 모든 내용을 다음과 같이 변경할 수 있습니다.

String s = "Your String with [Fields]";
for (Map.Entry<String, String> e : values.entrySet()) {
  s = s.replaceAll("\\[" + e.getKey() + "\\]", e.getValue());
}

String을 반복하여 맵의 요소를 찾을 수도 있습니다.그러나 []를 검색하는 String을 해석해야 하기 때문에 이것은 조금 더 복잡합니다.패턴과 매처를 사용하여 정규식을 사용할 수 있습니다.

${variable} 스타일 토큰을 대체하는 솔루션(여기에 나와 있는 답변과 Spring Uri Template에서 영감을 얻음)

public static String substituteVariables(String template, Map<String, String> variables) {
    Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}");
    Matcher matcher = pattern.matcher(template);
    // StringBuilder cannot be used here because Matcher expects StringBuffer
    StringBuffer buffer = new StringBuffer();
    while (matcher.find()) {
        if (variables.containsKey(matcher.group(1))) {
            String replacement = variables.get(matcher.group(1));
            // quote to work properly with $ and {,} signs
            matcher.appendReplacement(buffer, replacement != null ? Matcher.quoteReplacement(replacement) : "null");
        }
    }
    matcher.appendTail(buffer);
    return buffer.toString();
}

Apache Commons Library를 사용하면 Stringutils를 사용할 수 있습니다.replace 각:

public static String replaceEach(String text,
                             String[] searchList,
                             String[] replacementList)

매뉴얼에서 다음 항목을 참조하십시오.

다른 문자열 내의 모든 문자열을 바꿉니다.

이 메서드에 전달된 null 참조는 no-op입니다.또는 "검색 문자열" 또는 "교체할 문자열"이 null일 경우 해당 치환은 무시됩니다.이런 일은 반복되지 않습니다.반복 치환의 경우 오버로드된 메서드를 호출합니다.

 StringUtils.replaceEach(null, *, *)        = null

  StringUtils.replaceEach("", *, *)          = ""

  StringUtils.replaceEach("aba", null, null) = "aba"

  StringUtils.replaceEach("aba", new String[0], null) = "aba"

  StringUtils.replaceEach("aba", null, new String[0]) = "aba"

  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"

  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"

  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"

  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
  (example of how it does not repeat)

StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"

Apache Commons String Substitutor를 사용할 수 있습니다.

예를 들어 다음과 같습니다.

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

 // Build StringSubstitutor
 StringSubstitutor sub = new StringSubstitutor(valuesMap);

 // Replace
 String resolvedString = sub.replace(templateString);

산출:

 "The quick brown fox jumped over the lazy dog."

및 딜리미터 「」)를 할 .${ ★★★★★★★★★★★★★★★★★」}위의 예에서)를 사용하여 다음을 수행합니다.

다음과 같은 구문을 사용하여 기본값을 지정할 수도 있습니다.

String templateString = "The ${animal:giraffe} jumped over the ${target}.";

되면 렇렇 which which which which가 된다."The giraffe jumped over the lazy dog." 없을 때animal이치노

http://github.com/niesfisch/tokenreplacer

참고:

새로운 언어인 Kotlin에서는 "String Templates"를 소스 코드로 직접 사용할 수 있습니다.서드파티 라이브러리나 템플릿엔진이 변수 치환을 수행할 필요가 없습니다.

그것은 언어 자체의 특징이다.

참조: https://kotlinlang.org/docs/reference/basic-types.html#string-templates

예전에 String Template와 Groovy Templates에서 이러한 문제를 해결한 적이 있습니다.

궁극적으로 템플리트 엔진 사용 여부는 다음 요소에 기초해야 합니다.

  • 어플리케이션에 이러한 템플릿이 많이 포함되어 있습니까?
  • 애플리케이션을 재기동하지 않고 템플릿을 변경할 수 있는 기능이 필요합니까?
  • 이 템플릿은 누가 관리합니까?자바 프로그래머 또는 비즈니스 분석가가 프로젝트에 관여하고 있습니까?
  • 변수 값을 기반으로 한 조건부 텍스트와 같이 템플릿에 논리를 넣을 수 있는 기능이 필요합니까?
  • 템플릿에 다른 템플릿을 포함할 수 있는 기능이 필요합니까?

상기 중 하나가 귀사의 프로젝트에 적용된다면 대부분 이 기능을 제공하는 템플릿 엔진을 사용하는 것을 검토하고 있습니다.

나는 사용했다

String template = "Hello %s Please find attached %s which is due on %s";

String message = String.format(template, name, invoiceNumber, dueDate);

다음은 폼의 변수를 대체합니다.<<VAR>>맵에서 검색된 값.여기서 온라인으로 테스트할 수 있습니다.

예를 들어, 다음과 같은 입력 문자열을 사용합니다.

BMI=(<<Weight>>/(<<Height>>*<<Height>>)) * 70
Hi there <<Weight>> was here

및 다음 변수 값

Weight, 42
Height, HEIGHT 51

다음 출력을 나타냅니다.

BMI=(42/(HEIGHT 51*HEIGHT 51)) * 70

Hi there 42 was here

여기 코드가 있습니다.

  static Pattern pattern = Pattern.compile("<<([a-z][a-z0-9]*)>>", Pattern.CASE_INSENSITIVE);

  public static String replaceVarsWithValues(String message, Map<String,String> varValues) {
    try {
      StringBuffer newStr = new StringBuffer(message);
      int lenDiff = 0;
      Matcher m = pattern.matcher(message);
      while (m.find()) {
        String fullText = m.group(0);
        String keyName = m.group(1);
        String newValue = varValues.get(keyName)+"";
        String replacementText = newValue;
        newStr = newStr.replace(m.start() - lenDiff, m.end() - lenDiff, replacementText);
        lenDiff += fullText.length() - replacementText.length();
      }
      return newStr.toString();
    } catch (Exception e) {
      return message;
    }
  }


  public static void main(String args[]) throws Exception {
      String testString = "BMI=(<<Weight>>/(<<Height>>*<<Height>>)) * 70\n\nHi there <<Weight>> was here";
      HashMap<String,String> values = new HashMap<>();
      values.put("Weight", "42");
      values.put("Height", "HEIGHT 51");
      System.out.println(replaceVarsWithValues(testString, values));
  }

또한 요청은 하지 않았지만 동일한 방법을 사용하여 문자열 내의 변수를 application.properties 파일의 속성으로 바꿀 수 있습니다.다만, 이것은 이미 이루어지고 있을 가능성이 있습니다.

private static Pattern patternMatchForProperties =
      Pattern.compile("[$][{]([.a-z0-9_]*)[}]", Pattern.CASE_INSENSITIVE);

protected String replaceVarsWithProperties(String message) {
    try {
      StringBuffer newStr = new StringBuffer(message);
      int lenDiff = 0;
      Matcher m = patternMatchForProperties.matcher(message);
      while (m.find()) {
        String fullText = m.group(0);
        String keyName = m.group(1);
        String newValue = System.getProperty(keyName);
        String replacementText = newValue;
        newStr = newStr.replace(m.start() - lenDiff, m.end() - lenDiff, replacementText);
        lenDiff += fullText.length() - replacementText.length();
      }
      return newStr.toString();
    } catch (Exception e) {
      return message;
    }
  }

언급URL : https://stackoverflow.com/questions/959731/how-to-replace-a-set-of-tokens-in-a-java-string

반응형