簡體   English   中英

將字符串拆分為鍵值對

[英]Split string into key-value pairs

我有一個這樣的字符串:

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

現在:表示鍵值對,而::分隔鍵值對。 我想將鍵值對添加到地圖中。

我可以使用以下方法實現:

Map<String, String> map = new HashMap<String, String>();
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<String, String> map = new HashMap<String, String>();
    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<String, String> 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<String, String> 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<String, String> 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 毫秒。

試試這個代碼 - 請參閱注釋以獲取解釋:

HashMap<String,String> hmap = new HashMap<>();
String str="abc:1::xyz:2::jkl:3";
String straraay[]= str.split("::?");

for(int i=0;i<straraay.length;i+=2) {
    hmap.put(straraay[i],straraay[i+1]);
}

for(String s:straraay){
    System.out.println(hmap.values()); //for Values only
    System.out.println(hmap.keySet()); //for keys only if you want to more clear
}

我不知道這是否是最好的方法,但我認為這是在不使用 split 方法兩次的情況下做同樣事情的另一種方式

Map<String, String> map = new HashMap<String, String>();
String test = "pet:cat::car:honda::location:Japan::food:sushi";
String[] test1 = test.replaceAll("::",":").split(":");
for(int i=0;i<test1.length;i=i+2)
{
     map.put(test1[i], test1[i+1]);
}

for (String s : map.keySet()) {
    System.out.println(s + " is " + map.get(s));
}

希望它會有所幫助:)

這可能有用。 *utm_source=test_source&utm_medium=test_medium&utm_term=test_term&utm_content=test_content&utm_campaign=test_name&referral_code=DASDASDAS

   String str[] = referrerString.split("&");
                    HashMap<String,String> stringStringHashMap= new HashMap<>();
                    List<String> al;
                    al = Arrays.asList(str);
                    String[] strkey ;

                for (String s : al) {
                    strkey= s.split("=");
                    stringStringHashMap.put(strkey[0],strkey[1]);


                }
                for (String s : stringStringHashMap.keySet()) {
                    System.out.println(s + " is " + stringStringHashMap.get(s));
                }

你的程序絕對沒問題。

僅僅因為您要求更優化的代碼。

我通過使用少量變量而不是使用數組並將其存儲在其中來減少您的記憶。

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

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<String, String> 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM