如果我传递的字符串包含逗号分隔的键值对,就像这样
seller=1000,country="canada",address="123 1st st"
等
似乎必须有一种比解析然后迭代更好的方法。
根据Java中的密钥名称从此字符串中检索值的最佳方法是什么?
答案 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:我假设您已足够明白,如果值包含其中的分隔符(即逗号),此解决方案将无效...