java 在文本中展开环境变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4752817/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Expand environment variables in text
提问by Michael Smith
I'm trying to write a function to perform substitutions of environment variables in java. So if I had a string that looked like this:
我正在尝试编写一个函数来在 java 中执行环境变量的替换。所以如果我有一个看起来像这样的字符串:
User ${USERNAME}'s APPDATA path is ${APPDATA}.
用户 ${USERNAME} 的 APPDATA 路径是 ${APPDATA}。
I want the result to be:
我希望结果是:
User msmith's APPDATA path is C:\Users\msmith\AppData\Roaming.
用户 msmith 的 APPDATA 路径是 C:\Users\msmith\AppData\Roaming。
So far my broken implementation looks like this:
到目前为止,我损坏的实现如下所示:
public static String expandEnvVars(String text) {
Map<String, String> envMap = System.getenv();
String pattern = "\$\{([A-Za-z0-9]+)\}";
Pattern expr = Pattern.compile(pattern);
Matcher matcher = expr.matcher(text);
if (matcher.matches()) {
for (int i = 1; i <= matcher.groupCount(); i++) {
String envValue = envMap.get(matcher.group(i).toUpperCase());
if (envValue == null) {
envValue = "";
} else {
envValue = envValue.replace("\", "\\");
}
Pattern subexpr = Pattern.compile("\$\{" + matcher.group(i) + "\}");
text = subexpr.matcher(text).replaceAll(envValue);
}
}
return text;
}
Using the above sample text, matcher.matches()
returns false. However if my sample text, is ${APPDATA}
it works.
使用上面的示例文本,matcher.matches()
返回 false。但是,如果我的示例文本${APPDATA}
有效。
Can anyone help?
任何人都可以帮忙吗?
回答by jjnguy
You don't want to use matches()
. Matches will try to match the entire input string.
你不想使用matches()
. 匹配将尝试匹配整个输入字符串。
Attempts to match the entire region against the pattern.
尝试将整个区域与模式匹配。
What you want is while(matcher.find()) {
. That will match each instance of your pattern. Check out the documentation for find()
.
你想要的是while(matcher.find()) {
. 这将匹配您的模式的每个实例。查看 的文档find()
。
Within each match, group 0
will be the entire matched string (${appdata}
) and group 1
will be the appdata
part.
在每个匹配,group 0
将是整个匹配的字符串(${appdata}
)和group 1
将成为appdata
一部分。
Your end result should look something like:
您的最终结果应该类似于:
String pattern = "\$\{([A-Za-z0-9]+)\}";
Pattern expr = Pattern.compile(pattern);
Matcher matcher = expr.matcher(text);
while (matcher.find()) {
String envValue = envMap.get(matcher.group(1).toUpperCase());
if (envValue == null) {
envValue = "";
} else {
envValue = envValue.replace("\", "\\");
}
Pattern subexpr = Pattern.compile(Pattern.quote(matcher.group(0)));
text = subexpr.matcher(text).replaceAll(envValue);
}
回答by rfeak
If you don't want to write the code for yourself, the Apache Commons Lang library has a class called StrSubstitutor. It does exactly this.
如果您不想自己编写代码,Apache Commons Lang 库有一个名为StrSubstitutor的类。它正是这样做的。
回答by user2161699
The following alternative has the desired effect without resorting to a library:
以下替代方案无需求助于库即可达到预期效果:
- reads the map of environment variables once at startup
- on calling
expandEnvVars()
takes the text with potential placeholders as an argument - the method then goes through the map of environment variables, one entry at at time, fetches the entry's key and value
- and tries to replace any occurrence of
${<key>}
in the text with<value>
, thereby expanding the placeholders to their current values in the environment
- 在启动时读取一次环境变量的映射
- on call
expandEnvVars()
将带有潜在占位符的文本作为参数 - 然后该方法遍历环境变量的映射,一次一个条目,获取条目的键和值
- 并尝试用 替换
${<key>}
文本中出现的任何<value>
,从而将占位符扩展到它们在环境中的当前值
private static Map<String, String> envMap = System.getenv();
public static String expandEnvVars(String text) {
for (Entry<String, String> entry : envMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
text = text.replaceAll("\$\{" + key + "\}", value);
}
return text;
}
回答by lexx9999
Based on the accepted answer but without nested pattern replacement.
Supports also default value and underscores in env-name: ${env-var[:default]}
基于接受的答案,但没有嵌套模式替换。还支持 env-name 中的默认值和下划线:${env-var[:default]}
static String substituteEnvVars(String text) {
StringBuffer sb = new StringBuffer();
String pattern = "\$\{([A-Za-z0-9_]+)(?::([^\}]*))?\}";
Pattern expr = Pattern.compile(pattern);
Matcher matcher = expr.matcher(text);
while (matcher.find()) {
final String varname = matcher.group(1);
String envValue = System.getenv(varname);
if (envValue == null) {
envValue = matcher.group(2);
if (envValue == null)
envValue = "";
}
matcher.appendReplacement(sb, envValue);
}
matcher.appendTail(sb);
return sb.toString();
}
In additon variables are exactly substituted once. Text "${VAR}${X}" with VAR=${X} and X=x will be return "${X}x" not "xx".
此外,变量被精确替换一次。带有 VAR=${X} 和 X=x 的文本“${VAR}${X}”将返回“${X}x”而不是“xx”。
回答by Gray
I've taken @lexx9999 code and tweaked it a bit to use a StringBuilder
and handle a Map as well as environmental variables.
我采用了@lexx9999 代码并对其进行了一些调整以使用 aStringBuilder
并处理 Map 以及环境变量。
private final static Pattern ENV_VAR_PATTERN =
Pattern.compile("\$\{([A-Za-z0-9_.-]+)(?::([^\}]*))?\}");
/**
* Handle "hello ${var}", "${var:default}" formats for environ variable expansion.
*/
public static String substituteEnvVars(String text) {
return substituteEnvVars(text, System.getenv());
}
/**
* Handle "hello ${var}", "${var:default}", find var in replaceMap replace value.
*/
public static String substituteEnvVars(String text, Map<String, ?> replaceMap) {
StringBuilder sb = new StringBuilder();
Matcher matcher = ENV_VAR_PATTERN.matcher(text);
int index = 0;
while (matcher.find()) {
sb.append(text, index, matcher.start());
String var = matcher.group(1);
Object obj = replaceMap.get(var);
String value;
if (obj != null)
value = String.valueOf(obj);
else {
// if no env variable, see if a default value was specified
value = matcher.group(2);
if (value == null)
value = "";
}
sb.append(value);
index = matcher.end();
}
sb.append(text, index, text.length());
return sb.toString();
}
回答by DVK
Unless you're just trying to learn how to build things from scratch, you should not really bother implementing your own template engine - there are multitudes already available.
除非你只是想学习如何从头开始构建东西,否则你真的不应该费心去实现你自己的模板引擎——已经有很多可用的模板引擎了。
One very good one is FreeMarker(which has Java API). Here is a tutorial.
一个非常好的是FreeMarker(它具有Java API)。这是一个教程。