Развернуть переменные среды в тексте - PullRequest
14 голосов
/ 21 января 2011

Я пытаюсь написать функцию для выполнения замены переменных среды в Java.Поэтому, если бы у меня была строка, которая выглядела так:

Путь APPDATA пользователя $ {USERNAME} равен $ {APPDATA}.

Я хочу, чтобы результат был:

Путь APPDATA пользователя msmith - C: \ Users \ msmith \ AppData \ Roaming.

Пока моя сломанная реализация выглядит так:

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 ]

14 голосов
/ 21 января 2011

Вы не хотите использовать 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);
}
12 голосов
/ 21 января 2011

Если вы не хотите писать код для себя, в библиотеке Apache Commons Lang есть класс StrSubstitutor .Это именно так.

2 голосов
/ 06 июля 2018

Я взял код @ lexx9999 и немного его подправил, чтобы использовать StringBuilder и обрабатывать карту, а также переменные среды.

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();
}
2 голосов
/ 29 июня 2018

На основании принятого ответа, но без замены вложенного шаблона.Поддерживает также значение по умолчанию и подчеркивания в 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();
    }

В дополнении переменные точно подставляются один раз.Текст "$ {VAR} $ {X}" с VAR = $ {X} и X = x будет возвращен "$ {X} x", а не "xx".

2 голосов
/ 12 марта 2013
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;
}
0 голосов
/ 21 января 2011

Если вы просто не пытаетесь научиться создавать вещи с нуля, вам не стоит беспокоиться о реализации собственного механизма шаблонов - уже доступно множество .

Один очень хорошийодин из них - FreeMarker (который имеет Java API ).Вот учебник .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...