2016-10-02 8 views
3

Так что этот класс называется StrSubstitutor в org.apache.commons.lang3.text, который может взять на карте, как это:Java - извлечение пар ключ-значение из строки с помощью шаблона

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