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와 같은 템플릿 라이브러리를 사용해 볼 수 있습니다.
다음은 예를 제시하겠습니다.
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
'programing' 카테고리의 다른 글
도커 컨테이너 지연 시간 해결 방법 (0) | 2022.09.04 |
---|---|
라라벨에서 마리아와 천천히 많은 관계를 맺는다.DB (0) | 2022.09.04 |
java 로그로 행 번호를 인쇄하려면 어떻게 해야 합니까? (0) | 2022.09.04 |
매니페스트 사용Java의 MF 파일 (0) | 2022.09.04 |
Java 8 비교기 유형 추론에 매우 혼란스럽다. (0) | 2022.09.04 |