2016-10-02 2 views
3

を使用して文字列からキーと値のペアを抽出します。Javaの - したがって、このようなマップに取ることができますorg.apache.commons.lang3.textでStrSubstitutorと呼ばれるこのクラスがあるテンプレート

Map<String, String> params = new HashMap<String, String>(); 
params.put("name","Vivek"); 
params.put("id","900"); 
params.put("somethingelse","blah"); 

とこのようなテンプレート文字列:

<data> 
     <id>${id}</id> 
     <name>${name}</name> 
     <something>${somethingelse}</something> 
    </data> 

このような出力文字列を生成するために:私が欲しいもの

<data> 
     <id>900</id> 
     <name>Vivek</name> 
     <something>blah</something> 
    </data> 

は反対です。私は出力文字列とテンプレートをキーとしてテンプレート変数と値として文字列内の対応する値をマップに取り込むことができる方法はありますか?

PS - 私が使用する文字列は必ずしもXMLである必要はありません。これは一例です。

EDIT:変数名とタグ名が同じであるため、一部は混乱していると思います。タグは単なる例示であり、問​​題とは無関係です。私が心配している$ {}の中の変数です。私が意味することを示すために別のタグを追加しました。

+0

可能なタグのリスト( "id"、 "name"など)を知っていますか、または未知のタグの解決策が必要ですか? – c0der

+0

@ c0derタグは無関係です。あなたが変数を意味するなら - はい、それが未知の方が良いでしょう。基本的には、$ {}で囲まれたものを解析したいと思います –

+0

一般的で効率的なソリューションが必要な場合は、この構造を解析する必要があります。このような単純な例は、手書きパーサーで解析することができます。この例がより大きな仕様の一部である場合は、パーサジェネレータを検討する方が良いでしょう。 – CoronA

答えて

0

あなたが正規表現にフォーマット文字列を変換するためにパターンを使用して、例のクラス以下の入力文字列を、進行するために、この正規表現を使用することができます。

public final class FormatReader { 

    private final Pattern formatPattern; 
    private final List<String> names; 

    private FormatReader(
      final Pattern formatPattern, 
      final List<String> names) { 
     //// 
     this.formatPattern = formatPattern; 
     this.names = names; 
    } 

    public static FormatReader of(
      final String prefix, 
      final String suffix, 
      final String format) { 
     //// 
     return of(prefix, suffix, format, true); 
    } 

    public static FormatReader of(
      final String prefix, 
      final String suffix, 
      final String format, 
      final boolean allowSurroundingWhitespace) { 
     //// 
     // This method is somewhat ugly... 
     final List<String> names = new ArrayList<>(); 
     final StringBuilder sb = new StringBuilder("(?m)"); 
     boolean skip = allowSurroundingWhitespace; 
     if (skip) 
      sb.append("\\s*"); 
     for (int i = 0, last = 0, prefixLength = prefix.length(), suffixLength = suffix.length();;) { 
      if (i == format.length()) { 
       if (!skip) 
        sb.append(Pattern.quote(format.substring(last))); 
       break; 
      } 
      if (format.startsWith(prefix, i)) { 
       skip = true; 
       sb.append(Pattern.quote(format.substring(last, i))).append("(.+)"); 

       final int off = i + prefixLength; 
       names.add(format.substring(off, i = format.indexOf(suffix, off))); 
       i += suffixLength; 
       continue; 
      } 
      if (Character.isWhitespace(format.charAt(i))) { 
       if (!skip) { 
        skip = true; 
        // Replace '\s*' with '\s+' if at least one whitespace has to be present 
        sb.append(Pattern.quote(format.substring(last, i))).append("\\s*"); 
       } 
      } else if (skip) { 
       last = i; 
       skip = false; 
      } 
      i++; 
     } 
     if (!skip && allowSurroundingWhitespace) 
      sb.append("\\s*"); 
     return new FormatReader(Pattern.compile(sb.toString()), names); 
    } 

    public Map<String, String> toMap(
      final String input) { 
     //// 
     final Matcher m = formatPattern.matcher(input); 
     if (!m.matches()) 
      throw new IllegalArgumentException("Argument does not match format"); 
     final Map<String, String> map = new HashMap<>(); 
     for (int i = 0; i < m.groupCount();) 
      map.put(names.get(i), m.group(++i)); 
     return map; 
    } 

    public static void main(
      final String[] args) { 
     //// 
     final FormatReader r = of("${", "}", "" 
       + " <data>\n" 
       + "  <id>${id}</id>\n" 
       + "  <name>${name}</name>\n" 
       + " </data>"); 
     final String s = "" 
       + "  <data>\n" 
       + "  <id>900</id>   " 
       + " <name>Vivek</name>\n" 
       + " </data> "; 
     // The created pattern (accepts any count of whitespace): 
     //        'id'      'name' 
     // (?m)\s*\Q<data>\E\s*\Q<id>\E(.+)\Q</id>\E\s*\Q<name>\E(.+)\Q</name>\E\s*\Q</data>\E\s* 
     System.out.println(r.toMap(s)); // {name=Vivek, id=900} 
    } 
} 
+0

これは盲目的に実行されたときに機能します。説明のビットが役立つでしょう。 –

+0

さて、私はそれが今何をしているのか理解していると思います。答えをありがとう!私はあなたの答えを受け入れる前に誰かがこれを行うことができる既存の図書館を思い付くかどうかを見るでしょう。 –

+0

これで、コードが単一の空白を混乱させることに敏感であることがわかりました。文字列とテンプレートを一致させることができないので意味があります。残念ながら、これは私の問題ではあまりにも制限的です。 –

0

ここでは別のオプションです:

import java.util.HashMap; 
import java.util.Map; 

public class Test{ 

    public static void main(String[] args){ 

     //simulate template. Assuming no more than on param in line 
     String[] template = new String[]{ 
            "<data>", 
            "<id>${id}</id>", 
            "<name>${name}</name>", 
            "<something>${somethingelse}</something>", 
            "</data>" 
            }; 

     String[] output = new String[]{ 
            "<data>", 
            "<id>900</id>", 
            "<name>Vivek</name>", 
            "<somethingelse>blah</somethingelse>", 
            "</data>" 
            }; 

     Map<String, String> params = getParams(template); 

     getValues(params, output); 

     for(String key : params.keySet()) { 
      System.out.println(key +" : " + params.get(key)); 
     } 
    } 

    private static Map<String, String> getParams(String[] template) { 

     Map<String, String> params = new HashMap<String, String>(); 

     for (String line : template) { 

      //get location of 3 chars ${} 
      int index$ = line.indexOf("$"); 
      int indexLeftB = line.indexOf("{"); 
      int indexRightB = line.indexOf("}"); 

      //make sure all ${} are present 
      if((index$ <0) || (indexLeftB <0) || (indexRightB <0)) { 
       continue; 
      } 

      //make sure they are in the right order 
      if(((indexLeftB - index$) !=1) || (indexRightB < indexLeftB)) { 
       continue; 
      } 

      //get param 
      String param = getParamFromLine(line, indexLeftB+1 , indexRightB); 

      if(param != null) { 

       params.put(param,null); 
      } 
     } 

     return params; 
    } 

    private static void getValues(Map<String, String> params, String[] output) { 

     //iterate over map 
     for(String param : params.keySet()) { 

      String tag = "<"+param+">"; //like <name> 
      String closeTag = "</"+param+">"; //like <name> 

      //iterate over output 
      for(String line : output) { 

       line = line.trim(); //remove all whitespace 
       //look for first occurrence of patternToSearch 
       int index1 = line.indexOf(tag, 0); 
       int index2 = line.indexOf(closeTag, index1); 

       //make sure there are 2 occurrences in 
       if((index1 < 0) || (index2 < 0)) { 
        continue; 
       } 

       String value = getParamFromLine(line, index1+ tag.length(), index2); 
       if(value != null) { 

        params.put(param, value); 
       } 
      } 
     } 
    } 

    private static String getParamFromLine(String line, int indexLeftB, int indexRightB) { 

     String param = line.substring(indexLeftB, indexRightB); 

     return (param.trim().length() == 0) ? null : param.trim(); 
    } 
} 
+0

フィードバックをいただければ幸いです – c0der

関連する問題