从字符串java中检索值的最佳方法

时间:2011-05-04 17:40:11

标签: java string

如果我传递的字符串包含逗号分隔的键值对,就像这样

seller=1000,country="canada",address="123 1st st"

似乎必须有一种比解析然后迭代更好的方法。

根据Java中的密钥名称从此字符串中检索值的最佳方法是什么?

7 个答案:

答案 0 :(得分:7)

自版本10 Google Guava提供了一个类MapSplitter,它确实完成了这类事情:

Map<String, String> params = Splitter
    .on(",")
    .withKeyValueSeparator("=")
    .split("k1=v1,k2=v2");

答案 1 :(得分:2)

您可以创建自己的CSV解析器,它不是很复杂,但有一些角落情况可以解决,当然假设您使用的是标准CSV格式。

但为什么要重新发明轮子......

您可以尝试查找

之类的CSV解析器

还有其他人,环顾四周我相信你会找到一个适合你需要的。

答案 2 :(得分:0)

首先,您应该使用CSV解析库来解析逗号分隔值。 正确解析CSV数据并不像最初看起来那么简单。有很多good arguments没有重新发明那个轮子。

这也将来证明您的代码,并且是您无需测试或维护的代码。

我知道做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);       
}

答案 3 :(得分:0)

要用逗号分隔字符串,其他海报是正确的。最好使用CSV解析器(您自己的或OTS)。考虑引号内的逗号等可能导致许多未考虑的问题。

在表单中有每个单独的标记后:

key = "value"

我认为查找'='的第一个索引很容易。那之前的部分将是关键,之后的部分将是值。然后,您可以将它们存储在Map<String, String>中。 这假设您的密钥足够简单,并且不包含=等等。有时,当您可以限制问题范围时,采用简单的路径就足够了。

答案 4 :(得分:0)

通常你会想要将字符串解析成地图,因为你可能会多次提取各种值,所以通常需要预先支付解析费用。

如果没有,那么我将如何解决这个问题(假设你要区分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;
}

HTH

答案 5 :(得分:0)

如果你只想要一个这样的字符串中的一个值,你可以使用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;
}

答案 6 :(得分:-1)

使用String.split(yourdata, ','),您将获得String[]。然后,对每个条目执行String.split(String[i],"=")以分隔属性和值。

理想情况下,您应该在Properties对象实例中移动此数据。然后,您可以轻松地从XML保存/加载它。它有用的方法。

REM:我假设您已足够明白,如果值包含其中的分隔符(即逗号),此解决方案将无效...