Разбор строки Java - {k1 = v1, k2 = v2, ...} - PullRequest
8 голосов
/ 29 октября 2009

У меня есть следующая строка, которая, вероятно, будет содержать ~ 100 записей:

String foo = "{k1=v1,k2=v2,...}"

и ищу написать следующую функцию:

String getValue(String key){
    // return the value associated with this key
}

Я бы хотел сделать это без использования библиотеки разбора. Есть идеи для чего-то быстрого?

Ответы [ 7 ]

12 голосов
/ 29 октября 2009

Если вы знаете, что ваша строка всегда будет выглядеть так, попробуйте что-то вроде:

HashMap map = new HashMap();

public void parse(String foo) {
  String foo2 = foo.substring(1, foo.length() - 1);  // hack off braces
  StringTokenizer st = new StringTokenizer(foo2, ",");
  while (st.hasMoreTokens()) {
    String thisToken = st.nextToken();
    StringTokenizer st2 = new StringTokenizer(thisToken, "=");

    map.put(st2.nextToken(), st2.nextToken());
  }
}

String getValue(String key) {
  return map.get(key).toString();
}

Предупреждение: на самом деле я этого не пробовал; могут быть незначительные синтаксические ошибки, но логика должна быть разумной. Обратите внимание, что я также провёл проверку ошибок на ноль, поэтому вы можете сделать то, что я сделал, более надежным.

4 голосов
/ 29 октября 2009

Самый быстрый, но самый уродливый ответ, который я могу придумать, - это синтаксический анализ символа за символом с использованием конечного автомата. Это очень быстро, но очень специфично и довольно сложно. На мой взгляд, у вас может быть несколько состояний:

  • Ключ синтаксического анализа
  • Значение синтаксического анализа
  • Ready

Пример:

int length = foo.length();
int state = READY;
for (int i=0; i<length; ++i) {
   switch (state) {
      case READY:
        //Skip commas and brackets
        //Transition to the KEY state if you find a letter
        break;
      case KEY:
        //Read until you hit a = then transition to the value state
        //append each letter to a StringBuilder and track the name
        //Store the name when you transition to the value state
        break;
      case VALUE:
        //Read until you hit a , then transition to the ready state
        //Remember to save the built-key and built-value somewhere
        break;
   }
}

Кроме того, вы можете реализовать это намного быстрее, используя StringTokenizer (которые быстры) или Regexs (которые медленнее). Но в целом, разбор отдельных символов, скорее всего, самый быстрый способ.

2 голосов
/ 29 октября 2009

Если в строке много записей, возможно, лучше разбирать вручную без StringTokenizer для экономии памяти (в случае, если вам нужно проанализировать тысячи этих строк, стоит дополнительный код):


public static Map parse(String s) {
    HashMap map = new HashMap();
    s = s.substring(1, s.length() - 1).trim(); //get rid of the brackets
    int kpos = 0; //the starting position of the key
    int eqpos = s.indexOf('='); //the position of the key/value separator
    boolean more = eqpos > 0;
    while (more) {
        int cmpos = s.indexOf(',', eqpos + 1); //position of the entry separator
        String key = s.substring(kpos, eqpos).trim();
        if (cmpos > 0) {
            map.put(key, s.substring(eqpos + 1, cmpos).trim());
            eqpos = s.indexOf('=', cmpos + 1);
            more = eqpos > 0;
            if (more) {
                kpos = cmpos + 1;
            }
        } else {
            map.put(key, s.substring(eqpos + 1).trim());
            more = false;
        }
    }
    return map;
}

Я проверил этот код с этими строками, и он отлично работает:

{k1 = v1}

{k1 = v1, k2 = v2, k3 = v3, k4 = v4}

{k1 = v1,}

0 голосов
/ 25 октября 2012

Пожалуйста, найдите мое решение:

public class KeyValueParser {

    private final String line;
    private final String divToken;
    private final String eqToken;
    private Map<String, String> map = new HashMap<String, String>();

    // user_uid=224620; pass=e10adc3949ba59abbe56e057f20f883e;
    public KeyValueParser(String line, String divToken, String eqToken) {
        this.line = line;
        this.divToken = divToken;
        this.eqToken = eqToken;
        proccess();
    }

    public void proccess() {
        if (Strings.isNullOrEmpty(line) || Strings.isNullOrEmpty(divToken) || Strings.isNullOrEmpty(eqToken)) {
            return;
        }
        for (String div : line.split(divToken)) {
            if (Strings.isNullOrEmpty(div)) {
                continue;
            }
            String[] split = div.split(eqToken);
            if (split.length != 2) {
                continue;
            }
            String key = split[0];
            String value = split[1];
            if (Strings.isNullOrEmpty(key)) {
                continue;
            }
            map.put(key.trim(), value.trim());
        }

    }

    public String getValue(String key) {
        return map.get(key);
    }
}

Использование

KeyValueParser line = new KeyValueParser("user_uid=224620; pass=e10adc3949ba59abbe56e057f20f883e;", ";", "=");
String userUID = line.getValue("user_uid")
0 голосов
/ 29 октября 2009

Добавление кода для проверки существования key в foo оставлено читателю в качестве упражнения: -)

String foo = "{k1=v1,k2=v2,...}";

String getValue(String key){
    int offset = foo.indexOf(key+'=') + key.length() + 1;
    return foo.substring(foo.indexOf('=', offset)+1,foo.indexOf(',', offset));
}
0 голосов
/ 29 октября 2009

Ну, при условии, что в значениях нет ни «=», ни «,», самый простой (и потертый) метод:

int start = foo.indexOf(key+'=') + key.length() + 1;
int end =  foo.indexOf(',',i) - 1;
if (end==-1) end = foo.indexOf('}',i) - 1;
return (start<end)?foo.substring(start,end):null;

Да, не рекомендуется:)

0 голосов
/ 29 октября 2009

Написано без тестирования:

String result = null;
int i = foo.indexOf(key+"=");
if (i != -1 && (foo.charAt(i-1) == '{' || foo.charAt(i-1) == ',')) {
    int j = foo.indexOf(',', i);
    if (j == -1) j = foo.length() - 1;
    result = foo.substring(i+key.length()+1, j);
}
return result;

Да, это некрасиво: -)

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