将字符串拆分为键值对

我有一个像这样的字符串:

pet:cat::car:honda::location:Japan::food:sushi 

Now :表示键值对,而::分隔对。 我想将键值对添加到地图中。

我可以使用以下方法实现:

 Map map = new HashMap(); String test = "pet:cat::car:honda::location:Japan::food:sushi"; String[] test1 = test.split("::"); for (String s : test1) { String[] t = s.split(":"); map.put(t[0], t[1]); } for (String s : map.keySet()) { System.out.println(s + " is " + map.get(s)); } 

但有没有一种有效的方法呢?


我觉得代码是低效的,因为我使用了2个String[]对象并且调用了split函数两次。 另外,我使用t[0]t[1] ,如果没有值,可能抛出ArrayIndexOutOfBoundsException

您可以使用以下代码单独调用split()和String上的单个传递。 但它当然假设String首先是有效的:

  Map map = new HashMap(); String test = "pet:cat::car:honda::location:Japan::food:sushi"; // split on ':' and on '::' String[] parts = test.split("::?"); for (int i = 0; i < parts.length; i += 2) { map.put(parts[i], parts[i + 1]); } for (String s : map.keySet()) { System.out.println(s + " is " + map.get(s)); } 

上述内容可能比您的解决方案更有效,但如果您发现代码更清晰,那么请保留它,因为这种优化几乎没有机会对性能产生重大影响,除非您这样做数百万次。 无论如何,如果它如此重要,那么你应该测量和比较。

编辑:

对于那些想知道什么::? 在上面的代码中表示:String.split()将正则表达式作为参数。 分隔符是与正则表达式匹配的子字符串。 ::? 是一个正则表达式,意思是:1个冒号,后跟0或1个冒号。 因此它允许考虑:::作为分隔符。

使用Guava库它是一个单行:

 String test = "pet:cat::car:honda::location:Japan::food:sushi"; Map map = Splitter.on( "::" ).withKeyValueSeparator( ':' ).split( test ); System.out.println(map); 

输出:

 {pet=cat, car=honda, location=Japan, food=sushi} 

这也可能比JDK String.split更快,因为它不会为"::"创建正则表达式。

更新它甚至可以正确处理评论中的角落案例:

 String test = "pet:cat::car:honda::location:Japan::food:sushi:::cool"; Map map = Splitter.on( "::" ).withKeyValueSeparator( ':' ).split( test ); System.out.println(map); 

输出是:

 {pet=cat, car=honda, location=Japan, food=sushi, =cool} 

您的解决方案确实效率低下。

给你解析字符串的人也有点像小丑。 存在行业标准序列化格式,如JSON或XML,其中存在快速,有效的分析。 发明方形轮永远不是一个好主意。

第一个问题:你关心吗? 它是否足够慢以至于阻碍了应用程序的性能? 它可能不会,但只有一种方法可以找到答案。 对代码进行基准测试。

也就是说,存在更有效的解决方案。 以下是一个例子

 public static void main (String[] args) throws java.lang.Exception { String test = "pet:cat::car:honda::location:Japan::food:sushi"; boolean stateiskey = true; Map map = new HashMap<>(); int keystart = 0; int keyend = 0; int valuestart = 0; int valueend = 0; for(int i = 0; i < test.length(); i++){ char nextchar = test.charAt(i); if (stateiskey) { if (nextchar == ':') { keyend = i; stateiskey = false; valuestart = i + 1; } } else { if (i == test.length() - 1 || (nextchar == ':' && test.charAt(i + 1) == ':')) { valueend = i; if (i + 1 == test.length()) valueend += 1; //compensate one for the end of the string String key = test.substring(keystart, keyend); String value = test.substring(valuestart, valueend); keystart = i + 2; map.put(key, value); i++; stateiskey = true; } } } System.out.println(map); } 

该解决方案是仅具有两种状态的有限状态机。 它只查看每个字符两次,一次是在测试边界时,一次是将它复制到地图中的新字符串。 这是最低金额。

它不会创建不需要的对象,如字符串生成器,字符串或数组,这会使收集压力降低。

它保持良好的地方。 下一个字符可能总是在缓存中,因此查找很便宜。

它的成本很高,但可能不值得:

  • 它复杂得多,也不那么明显
  • 有各种各样的活动部件
  • 当字符串处于意外格式时,调试起来比较困难
  • 你的同事会恨你
  • 当你需要调试某些东西时,你会讨厌你

值得? 也许。 你需要多快解析一下这个字符串?

https://ideone.com/8T7twy上的一个快速而肮脏的基准测试告诉我,对于这个字符串,这种方法的速度大约快4倍。 对于较长的琴弦,差异可能会更大一些。

但是对于100.000次重复,你的版本仍然只有415毫秒,其中这个是99毫秒。

我不知道这是最好的方法,但我认为这是另一种做同样事情而不使用拆分方法两次的方法

 Map map = new HashMap(); String test = "pet:cat::car:honda::location:Japan::food:sushi"; String[] test1 = test.replaceAll("::",":").split(":"); for(int i=0;i 

希望它会有所帮助:)

你的程序绝对没问题。

只是因为你要求更优的代码。

我通过使用少量变量而不是将数组存储在其中来减少您的记忆。

看看你的字符串,它遵循一个模式。

key : value :: key : value ::....

我们能从中做些什么?

获取密钥直到它:一旦到达:获取值,直到它达到’::’。

 package qwerty7; import java.util.HashMap; public class Demo { public static void main(String ar[]) { StringBuilder s = new StringBuilder("pet:cat::car:honda::location:Japan::food:sushi"); boolean isKey = true; String key = "", value = ""; HashMap hm = new HashMap(); for(int i = 0; i < s.length(); i++) { char ch = s.charAt(i); char nextChar = s.charAt(i+1); if(ch == ':' && nextChar != ':') { isKey = false; continue; } else if(ch == ':' && nextChar == ':') { hm.put(key, value); isKey = true; key = ""; value = ""; i+=1; continue; } if(isKey) { key += ch; } else { value += ch; } if(i == s.length() - 1) { hm.put(key, value); } } for (String x : hm.keySet()) { System.out.println(x + " is " + hm.get(x)); } } } 

这样做不会在每次拆分时占用很多迭代次数。

不占用太多记忆。

时间复杂度O(n)

输出:

 car is honda location is Japan pet is cat food is sushi 
  HashMap hmap = new HashMap<>(); String str="abc:1::xyz:2::jkl:3"; String straraay[]= str.split("::?"); for(int i=0;i 

}