Ajuda com lógica de substring

Pessoal… Estou em um dia de “bloqueio mental” hoje… :cry: :oops:

Eu tenho uma String com varios “.”, e preciso pegar uma substring até um nível passado. Por exemplo:

Tenho a String “1.22.333.4444.55555”, e quero o terceiro nível, deve retornar “1.22.333”. Se quiser o quarto nível, retorna “1.22.333.4444”.

Só que nao consegui pegar algo como o indexOf predefinido, do tipo: “Quero a posicao da terceira ocorrência de tal caractere”…

Alguém pode me dar uma luz?

Ah… e preciso disso com um desempenho excelente, porque é um processo demorado e está em um laço quase que gigantesco…

Agradeço desde já

Cara usa StringTokenizer

http://java.sun.com/javase/6/docs/api/java/util/StringTokenizer.html

Dai ele separa a String principal em varios tokens (pedacos de string) separados e vc pega o indice que vc quiser.

já tentou o StringTokenizer?

vlw

Você pode usar o StringTokenizer usando o “.” como separador.

Ele vai te retornar um arry de strings, daí é só você fazer um “for” até o nivel que vc quer.

Valeu todo mundo

Eu que nao tava me lembrando do StringTokenizer… :oops:

Resolvi assim:

private static String getNivelComTokenizer(String str, int nroNivel){
    	StringTokenizer t = new StringTokenizer(str, ".");
    	String ret = "";
    	int i = 0;
    	while(t.hasMoreElements()){
    		ret += t.nextElement();
    		i++;
    		if(i == nroNivel){
    			break;
    		}
    		
    		//Preciso adicionar o .
    		ret += ".";
    	}
    	
    	return ret;
    }

Mas nem precisa de StringTokenizer… o método spit da classe String já faz o trabalho sujo…

String grandePalavra = "1.22.333.4444.55555.666666";
String palavras[] = grandePalavra.split("\.");
for (String s : palavras) {
	System.out.println(s);
}

Ou seja, a partir do índice do array palavras você pode pegar a parte que quiser.

[quote=marcobiscaro2112]Mas nem precisa de StringTokenizer… o método spit da classe String já faz o trabalho sujo…

String grandePalavra = "1.22.333.4444.55555.666666";
String palavras[] = grandePalavra.split("\.");
for (String s : palavras) {
	System.out.println(s);
}

Ou seja, a partir do índice do array palavras você pode pegar a parte que quiser.[/quote]

E qual modo é mais rápido, será?

Use Split que é mais rápido, StringTokenizer era o jeito antigo, com o foreach olha como o código ficou mais limpo!

Fiz um testezinho de desempenho, e o Tokenizer se saiu melhor:

Com este codigo:

[code]
public static void main(String[] sss) throws Exception {

	ArrayList<String> a = new ArrayList();
	
	for (int i = 0; i < 99999; i++) { // Inicializo o ArrayList
		a.add("1.2.3.4.5.6.7.8.9"); // com 9 niveis
	}
	
	long l = 0;
	
	for (int nroNivel = 1; nroNivel < 10; nroNivel++) {
		l = java.lang.System.currentTimeMillis();
		for (int i = 0; i < a.size(); i++) {
			getNivelTokenizer(a.get(i), nroNivel);
		}
		java.lang.System.out.println("Terminou " + nroNivel + " Tokenizer: " + (java.lang.System.currentTimeMillis() - l));

		l = java.lang.System.currentTimeMillis();
		for (int i = 0; i < a.size(); i++) {
			getNivelSplit(a.get(i), nroNivel);
		}
		java.lang.System.out.println("Terminou " + nroNivel + " Split    : " + (java.lang.System.currentTimeMillis() - l));
	}
	
}

private static String getNivelSplit(String str, int nroNivel){
	String[] palavras = str.split("\.");
	String ret = "";
	for(int i = 0; i < nroNivel; i++){
		ret += palavras[i] + ".";
	}
	ret = ret.substring(0, ret.length() - 1); // tiro o ultimo ponto
		
	return ret;
}

private static String getNivelTokenizer(String str, int nroNivel){
	StringTokenizer t = new StringTokenizer(str, ".");
	String ret = "";
	int i = 0;
	while(t.hasMoreElements()){
		ret += t.nextElement();
		i++;
		if(i == nroNivel){
			break;
		}
		
		//Preciso adicionar o .
		ret += ".";
	}
	
	return ret;
}[/code]

Eu obtive essa saída:

Terminou 1 Tokenizer: 44 Terminou 1 Split : 651 Terminou 2 Tokenizer: 83 Terminou 2 Split : 719 Terminou 3 Tokenizer: 173 Terminou 3 Split : 913 Terminou 4 Tokenizer: 265 Terminou 4 Split : 822 Terminou 5 Tokenizer: 455 Terminou 5 Split : 764 Terminou 6 Tokenizer: 421 Terminou 6 Split : 828 Terminou 7 Tokenizer: 606 Terminou 7 Split : 853 Terminou 8 Tokenizer: 860 Terminou 8 Split : 736 Terminou 9 Tokenizer: 665 Terminou 9 Split : 1010

Só mais uma coisa: eu usaria StringBuilder para as variáveis ret, pois melhora ainda mais o desempenho. Apesar de o Tokenizer se sair um pouco mais rápido em algumas vezes, como já dito ele já é um “idoso” e eu considero mais legível o código com o split. Mais aí vai de cada um.

[quote=thegoergen][quote=marcobiscaro2112]Mas nem precisa de StringTokenizer… o método spit da classe String já faz o trabalho sujo…

String grandePalavra = "1.22.333.4444.55555.666666";
String palavras[] = grandePalavra.split("\.");
for (String s : palavras) {
	System.out.println(s);
}

Ou seja, a partir do índice do array palavras você pode pegar a parte que quiser.[/quote]

E qual modo é mais rápido, será?[/quote]

po…testa ai… da um System.currentTimeMillis(); antes e depois do processo e subtrai o primeiro do segundo, o que da um valor menor é o mais rápido…

edit…até eu falar pra vc testar vc ja tinha feito…rs

De fato, também fiz uns testes e o StringTokenizer é mais rápido. Mas a diferença só é significativa para enormes quantidades. A média de diferença é de 0,1 milissegundo por iteração. A adaptação para o StringBuilder ficaria assim:

        // feito com Tokenizer
	public static String getNivelTokenizer(String s, int nivel) {
		StringTokenizer token = new StringTokenizer(s, ".");
		StringBuilder result = new StringBuilder();
		int i = 0;
		while (token.hasMoreElements()) {
			result.append(token.nextToken());
			if (++i == nivel) {
				break;
			}
			result.append(".");
		}
		return result.toString();
	}
	
	// feito com o split
	public static String getNivelSplit(String s, int nivel) {
		String[] niveis = s.split("\.");
		StringBuilder result = new StringBuilder();
		int i = 0;
		for (String a : niveis) {
			result.append(a);
			if (++i == nivel) {
				break;
			}
			result.append(".");
		}
		return result.toString();
	}

Realmente StringTokenizer é mais rápida que loucura, alguém me explica como uma classe antiga pode ser mais rápida:

package br.com.pedrosa.teste;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class Teste {
	public static void main(String[] sss) throws Exception {
		List<String> a = new ArrayList<String>();
		Teste teste = new Teste();
		for (int i = 0; i < 1000; i++) { // Inicializo o ArrayList
			a.add("1.2.3.4.5.6.7.8.9"); // com 9 niveis
		}
		for (int nroNivel = 1; nroNivel < 10; nroNivel++) {
			long tempoInicial = System.currentTimeMillis(); 
			for (int i = 0; i < a.size(); i++) {
				teste.getNivelTokenizer(a.get(i), nroNivel);
			}
			System.out.printf("Resultado Final StringTokenizer   %.3f ms%n", (System.currentTimeMillis() - tempoInicial)/ 1000d);
			
			for (int i = 0; i < a.size(); i++) {
				teste.getNivelSplit(a.get(i), nroNivel);
			}
			System.out.printf("Resultado Final Split   %.3f ms%n", (System.currentTimeMillis() - tempoInicial)/ 1000d);
			
		}

	}

	public String getNivelTokenizer(String s, int nivel) {
		StringTokenizer token = new StringTokenizer(s, ".");
		StringBuilder result = new StringBuilder();
		int i = 0;
		while (token.hasMoreElements()) {
			result.append(token.nextToken());
			if (++i == nivel) {
				break;
			}
			result.append(".");
		}
		return result.toString();
	}

	// feito com o split
	public String getNivelSplit(String s, int nivel) {
		String[] niveis = s.split("\.");
		StringBuilder result = new StringBuilder();
		int i = 0;
		for (String a : niveis) {
			result.append(a);
			if (++i == nivel) {
				break;
			}
			result.append(".");
		}
		return result.toString();
	}

}

Mas cuidado ao concatenar String evite o += sempre use StringBuilder com append.

Por que é mais rápida eu não sei, mas a documentação é bem clara quanto ao seu uso:

Ou seja, ainda existe apenas para compatibilidade com programas antigos. Não use em códigos novos! Use o split da classe String ou o pacote java.util.regex.

Usando StringBuilder ficou ainda mais rápido.

Valeu pra todo mundo, e me desculpem, mas eu já nem preciso mais disso, mudei minha lógica… :oops:

Sobre tokenizer ser antigo, ele deve ser mais simples talvez, por isso fica mais rápido… sei lá…