Строковый парсинг Java - {k1=v1, k2=v2, …}

Основные преимущества состоят в том, что можно создать уникальный идентификатор, не соединяясь с базой данных. И идентификатор глобально уникален, таким образом, можно легко объединить данные из различных баз данных. Они походят на небольшие преимущества, но сохранили меня большая работа в прошлом.

основные недостатки являются немного большим количеством необходимого устройства хранения данных (не проблема в современных системах), и идентификатор не действительно человекочитаемы. Это может быть проблемой при отладке.

существуют некоторые проблемы производительности как индексная фрагментация. Но те легко разрешимы (гуиды расчески jimmy nillson: http://www.informit.com/articles/article.aspx?p=25862 )

Редактирование объединило мои два ответа на этот вопрос

@Matt Sheppard, я думаю, что он подразумевает, что Вы можете дублирующиеся строки с различными GUID как первичные ключи. Это - проблема с любым видом суррогатного ключа, не просто GUID. И как он сказал, что это легко решено путем добавления многозначительных ограничений на уникальность данных к нестолбцам ключа. Альтернатива должна использовать естественный ключ, и у тех есть настоящие проблемы..

8
задан tinkertime 29 October 2009 в 15:53
поделиться

6 ответов

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

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

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

12
ответ дан 5 December 2019 в 09:26
поделиться

The speediest, but ugliest answer I can think of is parsing it character by character using a state machine. It's very fast, but very specific and quite complex. The way I see it, you could have several states:

  • Parsing Key
  • Parsing Value
  • Ready

Example:

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

In addition, you can implement this a lot faster using StringTokenizers (which are fast) or Regexs (which are slower). But overall, individual character parsing is most likely the fastest way.

4
ответ дан 5 December 2019 в 09:26
поделиться

If the string has many entries you might be better off parsing manually without a StringTokenizer to save some memory (in case you have to parse thousands of these strings, it's worth the extra code):


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

I tested this code with these strings and it works fine:

{k1=v1}

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

{k1= v1,}

2
ответ дан 5 December 2019 в 09:26
поделиться

Written without testing:

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;

Yes, it's ugly :-)

0
ответ дан 5 December 2019 в 09:26
поделиться

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

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
ответ дан 5 December 2019 в 09:26
поделиться

Добавление кода для проверки наличия ключа в 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
ответ дан 5 December 2019 в 09:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: