2012-05-16 50 views
7

我有以下字符串:
A:B:1111;domain:80;a;b
A是可選的,所以B:1111;domain:80;a;b也是有效的輸入。
:80是可以選擇的。所以B:1111;domain;a;b:1111;domain;a;b也是有效的輸入
我要的是一個String[]有落得:什麼是在這裏拆分字符串的好方法?

s[0] = "A"; 
s[1] = "B"; 
s[2] = "1111"; 
s[3] = "domain:80" 
s[4] = "a" 
s[5] = "b" 

我這樣做如下:

List<String> tokens = new ArrayList<String>(); 
String[] values = s.split(";"); 
String[] actions = values[0].split(":"); 

for(String a:actions){ 
    tokens.add(a); 
} 
//Start from 1 to skip A:B:1111 
for(int i = 1; i < values.length; i++){ 
    tokens.add(values[i]); 
} 
String[] finalResult = tokens.toArray(); 

我想知道有沒有更好的方法來做到這一點?我還能如何更有效地做到這一點?

+1

你試過:s.split(「[;:]」) 此正則表達式拆分爲一個字符是「 ;」或':' – rascio

+0

域名後面總會跟着一個'80'嗎? – codaddict

+0

@codaddict:沒有,也是可選的 – Jim

回答

2

這裏有很多不擔憂效率,我看到的是線性

無論如何,你可能要麼使用一個正則表達式或手動tokenizer。

您可以避開該列表。你知道的valuesactions長度,所以你可以做

String[] values = s.split(";"); 
String[] actions = values[0].split(":"); 
String[] result = new String[actions.length + values.length - 1]; 
System.arraycopy(actions, 0, result, 0, actions.legnth); 
System.arraycopy(values, 1, result, actions.length, values.length - 1); 
return result; 

它應該是合理有效的,除非你堅持自己實現split

未經測試的低級別的方法(使用前一定要進行單元測試和基準):

// Separator characters, as char, not string. 
final static int s1 = ':'; 
final static int s2 = ';'; 
// Compute required size: 
int components = 1; 
for(int p = Math.min(s.indexOf(s1), s.indexOf(s2)); 
    p < s.length() && p > -1; 
    p = s.indexOf(s2, p+1)) { 
    components++; 
} 
String[] result = new String[components]; 
// Build result 
int in=0, i=0, out=Math.min(s.indexOf(s1), s.indexOf(s2)); 
while(out < s.length() && out > -1) { 
    result[i] = s.substring(in, out); 
    i++; 
    in = out + 1; 
    out = s.indexOf(s2, in); 
} 
assert(i == result.length - 1); 
result[i] = s.substring(in, s.length()); 
return result; 

注:此代碼中,它只會在第一組分考慮:瘋狂的方式優化。處理最後一個組件有點棘手,因爲out將具有值-1

我通常會不是使用這最後的方法,除非性能和內存是非常關鍵的。最有可能的是,它仍然存在一些錯誤,並且代碼是相當難讀的,特別是與上面的代碼相比。

0

你可以做類似

String str = "A:B:1111;domain:80;a;b"; 
String[] temp; 

/* delimiter */ 
String delimiter = ";"; 
/* given string will be split by the argument delimiter provided. */ 
temp = str.split(delimiter); 
/* print substrings */ 
for(int i =0; i < temp.length ; i++) 
System.out.println(temp[i]); 
0

除非這是在你的代碼的瓶頸並已覈實那些不太擔心效率這裏的邏輯是合理的。您可以避免創建臨時數組列表,而是直接創建數組,因爲您知道所需的大小。

+0

我不知道這是否會成爲瓶頸。但我也有興趣學習其他方法來改進我的工作 – Jim

1

對於可接受的字符的一些假設,這個正則表達式提供驗證以及分裂到你想要的組。

Pattern p = Pattern.compile("^((.+):)?(.+):(\\d+);(.+):(\\d+);(.+);(.+)$"); 
Matcher m = p.matcher("A:B:1111;domain:80;a;b"); 
if(m.matches()) 
{ 
    for(int i = 0; i <= m.groupCount(); i++) 
     System.out.println(m.group(i)); 
} 
m = p.matcher("B:1111;domain:80;a;b"); 
if(m.matches()) 
{ 
    for(int i = 0; i <= m.groupCount(); i++) 
     System.out.println(m.group(i)); 
} 

給出:

A:B:1111;domain:80;a;b // ignore this 
A: // ignore this 
A // This is the optional A, check for null 
B 
1111 
domain 
80 
a 
b 

而且

B:1111;domain:80;a;b // ignore this 
null // ignore this 
null // This is the optional A, check for null 
B 
1111 
domain 
80 
a 
b 
0

如果你想保持域和端口在一起,那麼我相信你會需要你需要兩次拆分。你可以用一些正則表達式來實現它,但是我懷疑你會從中看到任何真正的性能收益。

如果你不介意分裂域和端口,則:

String s= "A:B:1111;domain:80;a;b"; 
    List<String> tokens = new ArrayList<String>(); 
    String[] values = s.split(";|:"); 

    for(String a : values){ 
     tokens.add(a); 
    } 
相關問題