Расширение переменных среды в тексте

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

Публичная статическая строка $ {USERNAME} String expandEnvVars ( текст строки ) { Map < String , String > envMap = System . getenv (); String pattern = "\ $ \ {([A-Za-z0-9] +) \}" ; Pattern expr = Pattern . компиляция ( шаблон ); Matcher matcher = expr . совпадение ( текст ); если ( совпадение , матчей ()) { для ( Int я = 1 ; я <= Matcher . groupCount (); я ++) { Строка envValue = EnvMap . получить ( согласовань . группа ( я ). toUpperCase ()); if ( envValue == null ) { envValue = "" ; } else { envValue = envValue . replace ( "\" , "\\" ); } Шаблон subexpr = Pattern . compile ( "\ $ \ {" + match . group ( i ) + "\}" ); text = subexpr . совпадение ( текст ). replaceAll ( envValue ); } } вернуть текст ; } путь - matcher.matches ().

Я хочу, чтобы результат был следующим:

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

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

${APPDATA}

Используя вышеприведенный образец текста, matches()возвращает false. Однако, если мой образец текста, while(matcher.find()) {это работает.

Может ли кто-нибудь помочь?

java,regex,

12

Ответов: 6


11 принят

Вы не хотите использовать matches(). Матчи будут пытаться соответствовать всей входной строке.

Попытка сопоставить весь регион с шаблоном.

Что вам нужно group 0. Это будет соответствовать каждому экземпляру вашего шаблона. Ознакомьтесь с документацией find().

В каждом матче group 1будет вся строка ( ${appdata}) и appdataбудет 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);
}

10

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


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

1

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


1

Я взял код @ 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();
}
ява, регулярное выражение,
Похожие вопросы