2012-05-16 22 views
7

Ho la seguente stringa:
A:B:1111;domain:80;a;b
Il A è opzionale in modo B:1111;domain:80;a;b è anche input valido.
Il :80 è opzionale e in modo B:1111;domain;a;b o :1111;domain;a;b sono anche validi ingresso
Quello che voglio è quello di finire con un String[] che ha:Qual è un buon modo per dividere le stringhe qui?

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

ho fatto questo come segue:

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(); 

Mi stavo chiedendo c'è un modo migliore per farlo? In quale altro modo potrei farlo in modo più efficiente?

+1

hai provato con: s.split ("[;:]") Questa scissione regex per un carattere che è ' ;' o ':' – rascio

+0

Il dominio sarà sempre seguito da un '80'? – codaddict

+0

@codaddict: No, questo è opzionale anche – Jim

risposta

2

non ci sono molte preoccupazioni di efficienza qui, tutto quello che vedo è lineari.

In ogni caso, è possibile che utilizzi un'espressione regolare o un tokenizzatore manuale.

È possibile evitare l'elenco. Si conosce la lunghezza di values e actions, in modo da poter fare

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; 

dovrebbe essere ragionevolmente efficiente, a meno che non ti ostini a implementare split te stesso.

testato approccio di basso livello (assicurarsi unit test e benchmark prima dell'uso):

// 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; 

Nota: questo codice è ottimizzato in modo folle che considererà una : solo nel primo componente . La gestione dell'ultimo componente è un po 'complicata, poiché out avrà il valore -1.

Io di solito non utilizzare questo ultimo approccio, a meno che le prestazioni e la memoria siano estremamente cruciali. Molto probabilmente ci sono ancora alcuni bug in esso, e il codice è abbastanza illeggibile, in particolare rispetto a quello sopra.

0

si potrebbe fare qualcosa di simile

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

A meno che questo è un collo di bottiglia nel codice e si è verificato che non ti preoccupare molto di efficienza, come la logica qui è ragionevole. È possibile evitare di creare l'elenco di array temporaneo e invece creare direttamente l'array come si conosce la dimensione richiesta.

+0

Non so se questo è o sarà un collo di bottiglia. Ma sarei interessato ad imparare anche altri modi per il mio miglioramento – Jim

1

Con alcune ipotesi sui caratteri accettabili, questa espressione regolare fornisce la convalida e la suddivisione nei gruppi desiderati.

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)); 
} 

Dà:

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 

E

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

Se si desidera mantenere il dominio e la porta insieme, quindi credo che avrete bisogno di due divisioni. Potresti riuscire a farlo con qualche regex magic, ma dubito che ne vedrai dei reali guadagni in termini di prestazioni.

Se non ti dispiace dividere il dominio e la porta, poi:

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); 
    } 
Problemi correlati