在文本中展开环境变量

时间:2011-01-20 21:29:41

标签: java regex

我正在尝试编写一个函数来在java中执行环境变量的替换。所以如果我有一个看起来像这样的字符串:

  

用户$ {USERNAME}的APPDATA路径是   $ {APPDATA}。

我希望结果是:

  

用户msmith的APPDATA路径是   C:\ Users \用户msmith \应用程序数据\漫游

到目前为止,我的破坏实现看起来像这样:

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;
}

使用上面的示例文本,matcher.matches()返回false。但是,如果我的示例文本为${APPDATA}则可行。

有人可以帮忙吗?

6 个答案:

答案 0 :(得分:14)

您不想使用matches()。匹配将尝试匹配整个输入字符串。

  

尝试将整个区域与模式匹配。

你想要的是while(matcher.find()) {。这将匹配您的模式的每个实例。查看find()的文档。

在每场比赛中,group 0将是整个匹配的字符串(${appdata}),group 1将是appdata部分。

您的最终结果应如下所示:

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);
}

答案 1 :(得分:12)

如果您不想自己编写代码,那么Apache Commons Lang库就有一个名为StrSubstitutor的类。它就是这样做的。

答案 2 :(得分:2)

public static String expandEnvVars(String text) {        
    Map<String, String> envMap = System.getenv();       
    for (Entry<String, String> entry : envMap.entrySet()) {
        String key = entry.getKey();
        String value = entry.getValue();
        text = text.replaceAll("\\$\\{" + key + "\\}", value);
    }
    return text;
}

答案 3 :(得分:2)

基于可接受的答案,但没有嵌套模式替换。 还支持默认值和env名称中的下划线:${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();
    }

另外,变量被完全替换一次。具有VAR = $ {X}和X = x的文本“ $ {VAR} $ {X}”将返回“ $ {X} x”而不是“ xx”。

答案 4 :(得分:2)

我已经使用@ lexx9999代码,并对其进行了一些微调,以使用StringBuilder来处理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();
}

答案 5 :(得分:0)

除非你只是想学习如何从头开始构建东西,否则你不应该真的费心实现自己的模板引擎 - 有multitudes already available

一个非常好的是FreeMarker(有Java API)。这是tutorial

相关问题