2011-01-20 15 views
8

javaで環境変数の置換を実行する関数を作成しようとしています。したがって、このような文字列がある場合:テキスト内の環境変数を展開する

ユーザー$ {USERNAME}さんのAPPDATAパスは $ {APPDATA}です。

私は結果になりたい:\ Users \ユーザーmsmith \のAppData \ローミング:

ユーザーmsmithのAPPDATAパスは Cです。

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

falseを返しますmatcher.matches()上記のサンプルテキストを、使用:

これまでのところ、私の壊れた実装では、このようになります。しかし、私のサンプルテキストが${APPDATA}であれば動作します。

誰でも手助けできますか?

答えて

8

matches()を使用しないでください。マッチは入力文字列全体を照合しようとします。

パターンに対して領域全体を一致させようとします。

希望するものはwhile(matcher.find()) {です。それはパターンの各インスタンスに一致します。 find()のドキュメントをご覧ください。

group 0は一致する文字列全体(${appdata})、group 1appdataとなります。 multitudes already availableがあります - あなただけのゼロから物事を構築する方法を学習しようとしている場合を除き、あなたは本当にあなた自身のテンプレートエンジンを実装する気にはならない、

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

これは機能します。ありがとう! –

+0

@Michael、あなたは大歓迎です。 – jjnguy

+0

この場合、返された文字列の$ {}部分をエスケープする必要があるため、matcher.group(0)を使用した例がスローされます。だから代わりに式の代わりに "\\ $ \\ {" + matcher.group(1)+ "\\}"を使いました。 –

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

+1。これはライブラリよりコンパクトです。パスを持つウィンドウの下で作業するとき、私は 'String value = entry.getValue()を好む。"\" charはエスケープとして解釈され、無効なパスとなるため、置換( '\\'、 '/'); 'を使用します。 – k3b

+0

受け入れられた解決策は機能しますが、正規表現。 –

+1

@Dave C String#replaceAllはフードの中で正規表現を使用します – Bax