Лучший способ получить значение из строки Java - PullRequest
0 голосов
/ 04 мая 2011

Если мне передают строку, содержащую пары ключ-значение, разделенные запятыми, например,

seller=1000,country="canada",address="123 1st st" и т. Д.

Кажется, что должен быть лучший способ, чем анализперебирая

Каков наилучший способ получить значение из этой строки на основе имени ключа в Java?

Ответы [ 7 ]

7 голосов
/ 04 октября 2011

С момента выпуска 10 Google Guava предоставляет класс MapSplitter , который делает именно такие вещи:

Map<String, String> params = Splitter
    .on(",")
    .withKeyValueSeparator("=")
    .split("k1=v1,k2=v2");
2 голосов
/ 04 мая 2011

Вы можете создать свой собственный синтаксический анализатор CSV, он не очень сложен, но есть несколько угловых случаев, которые нужно учитывать, если, конечно, вы используете стандартный формат CSV.

Но зачем изобретать велосипед ...

Вы можете попробовать найти синтаксический анализатор CSV, например

Есть и другие, оглянись. Я уверен, ты найдешь ту, которая соответствует твоим потребностям.

0 голосов
/ 05 мая 2011

Если вы просто хотите получить одно значение из такой строки, вы можете использовать методы String indexOf () и substring ():

String getValue(String str, String key)
{
    int keyIndex = str.indexOf(key + "=");

    if(keyIndex == -1) return null;

    int startIndex = str.indexOf("\"", keyIndex);
    int endIndex = str.indexOf("\"", startIndex);
    String value = str.substring(startIndex + 1, endIndex);
    return value;
}
0 голосов
/ 04 мая 2011

Обычно вы захотите проанализировать строку в карте, потому что вы будете извлекать различные значения, возможно, несколько раз, поэтому часто имеет смысл оплатить стоимость анализа заранее.

Если нет, то вот как я бы решил эту проблему (при условии, что вы хотите провести различие между значениями int и значениями String).:

public Object pullValue(String pairs, String key) {
    boolean returnString = false;
    int keyStart = pairs.indexOf(key + "=");
    if (keyStart < 0) {
        logger.error("Key " + key + " not found in key-value pairs string");
        return null;
    }
    int valueStart = keyStart + key.length() + 1;
    if (pairs.charAt(valueStart) == '"') {
        returnString = true;
        valueStart++;    // Skip past the quote mark
    }
    int valueEnd;
    if (returnString) {
        valueEnd = pairs.indexOf('"', valueStart);
        if (valueEnd < 0) {
            logger.error("Unmatched double quote mark extracting value for key " + key)
        }
        return pairs.substring(valueStart, valueEnd);
    } else {
        valueEnd = pairs.indexOf(',', valueStart);
        if (valueEnd < 0) {  // If this is the last key value pair in string
            valueEnd = pairs.length();
        }
        return Integer.decode(pairs.substring(valueStart, valueEnd));
    }

}

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

Другое решение - использовать синтаксический анализатор регулярных выражений. Вы можете сделать что-то вроде (это не проверено):

Pattern lookingForString = Pattern.compile(key + "[ \t]*=[ \t]*[\"]([^\"]+)[\"]");
Pattern lookingForInt = Pattern.compile(key + "[ \t]*=[ \t]*([^,]+)");
Matcher stringFinder = lookingForString.matcher(pairs);
Matcher intFinder = lookingForInt.matcher(pairs);
if (stringFinder.find()) {
    return stringFinder.group(1);
} else if (intFinder.find()) {
    return Integer.decode(intFinder.group(1));
} else {
    logger.error("Could not extract value for key " + key);
    return null;
}

НТН

0 голосов
/ 04 мая 2011

Чтобы отделить строку запятыми, остальные плакаты верны. Лучше всего использовать парсер CSV (ваш или OTS). Учет таких вещей, как запятые внутри кавычек и т. Д., Может привести к множеству неучтенных проблем.

Как только у вас есть каждый отдельный токен в форме:

key = "value"

Я думаю, что достаточно просто найти первый индекс '='. Тогда часть до этого будет ключом, а часть после этого будет значением. Тогда вы можете хранить их в Map<String, String>. Это предполагает, что ваши ключи будут достаточно простыми и не будут содержать = в них и т. Д. Иногда достаточно выбрать простой маршрут, когда вы можете ограничить область действия проблемы.

0 голосов
/ 04 мая 2011

Используйте String.split(yourdata, ','), и вы получите String[]. Затем выполните String.split(String[i],"=") для каждой записи, чтобы отделить свойство и значения.

В идеале вы должны переместить эти данные в Properties экземпляр объекта. Затем вы можете легко сохранить / загрузить его из XML. У него есть полезные методы.

REM: Я предполагаю, что вы достаточно опытны, чтобы понять, что это решение не будет работать, если значения содержат разделитель (то есть запятую) в них ...

0 голосов
/ 04 мая 2011

Прежде всего вы должны использовать библиотеку CSV для анализа значений, разделенных запятыми. Правильно анализ данных CSV не так тривиален, как кажется на первый взгляд.Есть множество веских аргументов , чтобы не изобретать это колесо.

Это также будет проверять в будущем ваш код и будет кодом, который вам не нужно тестировать или поддерживать.

Я знаю, что соблазн сделать что-то вроде data.split(','); силен, но это хрупкое и хрупкое решение.Например, что если какое-либо из значений содержит символ ','.

Второе, что вам нужно сделать, - это затем проанализировать пары.Снова искушение использовать String.split("="); будет сильным, но оно может быть хрупким и хрупким, если в правой части = есть =.

Я не слепой сторонник регулярных выражений, но при сдержанности они могут быть просто подходящим инструментом для работы.Вот регулярное выражение для разбора пар имя-значение.

Регулярное выражение ^ (. *) \ S? = \ S? ("? ([^"] *) "? |"(. *) ") $ , щелкните регулярное выражение, чтобы проверить его в интерактивном режиме. Это работает даже для нескольких двойных кавычек в правой части пары имя-значение.

Это будет соответствовать только тому, чтонаходится с левой стороны от первого =, а все остальное с правой стороны и убирает необязательные значения " со строковых значений, в то же время сопоставляя значения без кавычек.

УчитываяList<String> list кодированных пар имя-значение.

final Pattern p = Pattern.compile("^(.*)\s?=\s?("?([^"]*)"?|"(.*)")$");
final Map<String, String> map = new HashMap<String, String>(list.size());
for (final String nvp : list)
{
    final Matcher m = p.matcher(nvp);
    m.matches();
    final String name = m.group(1);
    final String value = m.group(2);
    System.out.format("name = %s | value = %s\n", name, value);       
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...