Expressão Regular + Tabela + List

9 respostas
F

Pessoal, estou com outro problemão aki,

Eu preciso pegar as informações de uma tabela em html atraves de expressões regulares, e esse não é o problema. Eu construi a expressão que obtem as informações de uma linha da tabela. O problema é como eu faço para “dizer” : “Obtive a primeira linha, ótimo, agora eu continuo fzendo a pesquisa desse ponto em diante”. Seria mais ou menos como dar “um loop” na expressão, se é q eu posso falar isso. Mais ou menos eu defino o começo da area da busca a partir da ultima linha eu pegar. Só que eu não consegui fazer isso, ou seja, apenas pego a primeira linha. Olhem o cogido HTML

<tr bgcolor="#dababa">
		<td nowrap>
						1520381
		</td>
		<td>
			<a href="/tracker/index.php?func=detail&aid=1520381&group_id=16696&atid=116696">
				Source typo
			</a>
		</td>

		<td>
							&nbsp;
						2006-07-11 00:39
		</td>
		<td align="center">
			5
		</td>

				
		<td><a href="/tracker/index.php?func=detail&aid=1520381&group_id=16696&atid=116696">Notes</a></td>
		<td>nobody</td>

	</tr>
	<tr bgcolor="#dababa">
		<td nowrap>
						1238050
		</td>
		<td>
			<a href="/tracker/index.php?func=detail&aid=1238050&group_id=16696&atid=116696">
				Error for priest spell recharging ?
			</a>
		</td>

		<td>
							<b>*
						2005-07-14 02:16
		</td>
		<td align="center">
			5
		</td>

				
		<td>nobody</td>
		<td>nobody</td>

	</tr>

/Depois disso eu armazeno numa List. Só que eu não consegui pegar as outras linhas, apenas a primeira.
Aki estão as minhas expressões

Pattern expression = Pattern.compile(
					"<td nowrap>\n\s*(.*?)"	 								+	//Id
					"\n\s*</td>\n\s*<td>\n\s*<a (.*?)>\n\s*(.*?)" 		 	+	//BugName
					"\n\s*</a>\n\s*</td>\n\s*<td>\n\s*(.*?)\n\s*(.*?)\n" 	+	//BugDate
					"\s*</td>\n\s*<td align=\"center\">\n\s*(.*?)\n" 		+	//Priority
					"\s*</td>\n\s*\n\s*<td>(.*?)</td>\n"						+	//AssignedTo
					"\s*<td><a href=\"(.*?)>(.*?)</a></td>")						/*SubmitedBy*/;

Alguém tem uma solução?
Obrigado

9 Respostas

M

Olá, felixcomputer!
Fiz um exemplinho que talvez te ajude. Dá uma olhada (e testa aí na sua máquina)

public class TesteMatcher{
	public void testMatcher() {
		String text = 
			"Some HTM Color Codes:\n\n" +
			"\t#DC143C\tCrimson\n" +
			"\t#ff6347\tTomato\n" +
			"\t#ffE4B5\tMoccasin\n" +
			"\t#4B0082\tIndigo\n" +
			"\t#fffFf0\tIvory\n" +
			"\t#f5DEB3\tWheat\n" +
			"So... that's it! Enjoy it!"
		;
		String regex = "#[0-9A-Fa-f]{6}";
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(text);
		
		System.out.println(text);
		System.out.println();
		System.out.println("Seraching for the pattern " + regex + " in the text above:");
		while(matcher.find()) {
			int pos = matcher.start();
			System.out.println(
				"\tPattern found at position " + pos + 
				"(\"" + text.substring(pos, pos + 13) + "...\")"
			);
		}
	}
	
	public static void main(String[] args) {
		try{
			Testes app = new Testes();
			app.testMatcher();
		}catch(Throwable t) {
			t.printStackTrace();
		}finally{
			System.exit(0);
		}
	}
}

O método find() da classe Matcher busca, no String(No CharSequence, pra ser mais exato) a ele associado, por algum casamento do Pattern nele armazenado. Quando ele acha, ele retorna true. Caso contrário, false.
Mas isso não adianta muito, pois como vamos saber onde foi encontrado o Pattern dentro do String??? Quando o find() retorna true, a classe Matcher marca internamente a posição do String onde conseguiu casar o Pattern. Essa posição pode ser recuperada através do método start(), que retorna onde no String o Matcher está… er… “parado”, por assim dizer… :thumbup:
Qq coisa, pergunte mais, ok!

F

Cara, valeu, foi mais simples do q eu pensava. Valeu msm
Tem mais uma coisa cara,

Em um dos campos eu posso ter um resultado diferente, ora eu vou ter nobody e ora eu vou ter o nome de alguem com um link, no caso algo do tipo

<td>nobody</td>  ou
<td><a href="/tracker/index.php?func=detail&aid=1238050&group_id=16696&atid=116696">Matum</a>

Eu tentei passar isso para a expressão dessa forma, para obter ou o Matum ou o nobody:

("nobody"|"<a href=/"(.*?)>(.*?)</a>)

Para ver se ele reconhecia um dos dois padrões, isso pode ser meio besta, mas como eu faço?
Valeu cara, tu ta me ajudando muito :thumbup:
Samuel

M

É quase desse jeito mesmo! Vc só naum pode esquecer que a regex é uma String, entaum tem que estar tudo dentro de aspas. Tente algo assim:

String regex = "(nobody)|(<a href=/(.*?)>(.*?)</a>)";

qq coisa, poste mais!

F

Naum, deu erro, na verdade, eu estou querendo obter uma informação, que é o nome do cara, no caso com link eu pego o segundo grupo (.*?) ou se ninguem assinou, no caso nobody, é aquele mesmo caso anterior de obter uma informação na pagina, só que se eu construir a expressão para o link naum vai funcionar para o nobody e vice-versa, por isso quero construir uma expressão q aceite os dois casos, olha la em cima, no exemplo da tabela,
q q eu faço?

M

Vc reparou que na expressão que eu te passei agora naum temos apenas dois [i]matching groups/i, e sim 4? Olhe só:
mg 1:
[list]nobody[/list]
mg 2:
[list](.?)[/list]
mg 3:
[list].? //O primeiro, da esquerda pra direita[/list]
mg 4:
[list].? //O segundo, da esquerda pra direita[/list]
Se o seu programa estava ainda contando em analisar, ou "pegar o segundo mg, entaum danou-se… daí deu erro mesmo… porque provavelmente ele esperava um trem assim:
.
?
mas recebeu um trem assim:
(.*?)
aí é só doidera mesmo… :lol:
Prmeiro de tudo, acho legal vc marcar cada mg que vc naum vai usar para fins de reaproveitamento (aquele $1, $2, etc…) como um [i]non-matching group/i:

String regex = "(?:nobody)|(?:<a href=/(.*?)>(.*?)</a>)";

O “?:” logo após o “(” indica que este grupo não será armazenado.
Quanto ao seu problema, acho que vais ter mudar a abordagem mesmo… vou pensar em algo, ok :thumbup:

M

Supondo a regex assim agora

String regex = "(nobody)|(?:<a href=/(:?.*?)>(.*?)</a>)";

Naum teria como vc ajustar sua lógica para pegar sempre o mg01 e o mg02? se o mg01 for diferente de vazio, entaum temos que olhar o mg02, caso contrário, temos um “nobody”

F

Cara eu entendi o teu raciocinio e achei muito bom, acredito que deve dar certo,contudo eu implementei e deu errado, podes ver se eu to fazendo algo errado: Valeu cara

public void getBug(String BugsPageURL) 
	{
		try
		{
			
			Pattern expression = Pattern.compile(
					"<td nowrap>\n\s*(.*?)"	 								+	//Id
					"\n\s*</td>\n\s*<td>\n\s*<a (.*?)>\n\s*(.*?)" 		 	+	//BugName
					"\n\s*</a>\n\s*</td>\n\s*<td>\n\s*(.*?)\n\s*(.*?)\n" 	+	//BugDate
					"\s*</td>\n\s*<td align=\"center\">\n\s*(.*?)\n" 		+	//Priority
					"(?:nobody)|(?:<a href=\"(.*?)\">(.*?)</a>)"
					/*"\s*</td>\n\s*\n\s*<td><a href=\"(.*?)\">(.*?)</a><a (.*?)</td>"*/		+	//AssignedTo
					"\s*<td><a href=\"(.*?)\">(.*?)<")						/*SubmitedBy*/;
			
			Matcher matcher = expression.matcher(BugsPageURL);
			while ( matcher.find() )
				{
					requestId = Long.parseLong(matcher.group(1));
					summary = matcher.group(3);
					BugData = matcher.group(5);
					Priority = Long.parseLong(matcher.group(6));
					if( matcher.group(8) != null)
					{
						if(matcher.group(9).equals(null))
						{
							AssignedTo = "nobody";
						}
					}
					else
					{
						AssignedTo = matcher.group(11);
					}
					SubmittedBy = matcher.group(12);
					

					System.out.println("requestId: "+requestId+" \tsummary: "+summary+" \tBugData: "+BugData+" Priority: \t"+Priority+" \tAssignedTo: "+AssignedTo+"\t SubmittedBy: "+SubmittedBy);
					
				}
		}
		catch(Exception e)
		{
			new Exception("Não pude extrair o bug");
		}
		
	}
M

Olha só como são as coincidências… hoje mesmo eu tava tendo problemas com umas regex que eu montei. Estava assim antes:

public static final String
	SIMPLE_VALID_LABLE = "a",
	SIMPLE_VALID_ACTION = "#{a.a}",
	PROP_SEP = ";",
	VALID_ID_PATTERN = "[1-9]|10",
	VALID_LABLE_PATERN = "[^)|(,;]+",
	VALID_ACTION_PATTERN = "#\{[A-Za-z]\w*\.[A-Za-z]\w*\}",
	VALID_STR_PATTERN = 
		VALID_ID_PATTERN + PROP_SEP +
		VALID_LABLE_PATERN + PROP_SEP +
		VALID_ACTION_PATTERN
;

A idéia é eu conseguir reconhecer, por exemplo, uns Strings assim:
[list]“8;SGR->Adicionar Usuário;#{XXCo_Blala.doAddUser}”[/list]
[list]“5;COB->Excluir Boleto;#{XXCo_Ononon.doDelBol}”[/list]
[list]“9;TECH->Gerenciar versão;#{XXCo_Tech.doGerVer}”[/list]

Perceba que essas strings estão quebradas em 3 setores, delimitados por “;”. O primeiro eu chamo de “id”, o segundo de “lable” e o terceiro de “action”. Tive meus motivos pra fazer um regex pra cada um separado:
[list]id: um número entre 1 e 10, inclusive[/list]
[list]lable: um String qualquer que não tenha os caracteres “)”, “|”, “(”, “,” e “;”[/list]
[list]action: um String com a cara de um expressionString de um javax.faces.el.MethodBinding[/list]

Quando eu testava as partes independentemente, dava tudo certinho:

//Syso -> System.out.println(...);
Syso("8".matches(VALID_ID_PATTERN));
Syso("SGR->Adicionar Usuário".matches(VALID_LABLE_PATTERN));
Syso("#{XXCo_Blala.doAddUser}".matches(VALID_ACTION_PATTERN));

Isso vai soltar no console:

true
true
true

Só que, quando eu fui testar a coisa como um todo:

Syso("8;SGR->Adicionar Usuário;#{XXCo_Blala.doAddUser}".matches(VALID_STR_PATTERN));

Tava dando false… Mas como!!! Por quê??? Se eu apenas juntei as regex???
Demorei um bocado pra descobrir… Era o maldito “ou” da regex (o caractere pipe: “|”)… Essa desgraça pelada parece que tem precedência máxima na compilação da regex… Minha regex geral estva se comportando assim: Só aceite o String
[list]ou se for um número de 1 a 9…[/list]
[list]ou se for um String “10”, seguido de um “;”, seguido de um String qualquer que não tenha os caracteres “)”, “|”, “(”, “,” e “;”, seguindo de um String com a cara de um expressionString de um javax.faces.el.MethodBinding[/list]
Aí já viu a confusão…
Resolvi o problema agrupando o meu “ou”:

...
VALID_ID_PATTERN = "(?:[1-9]|10)",
...

É tente corrigir isso aí no “ou” que tem no meio daquela tua singela regex, ok?
Se continuar dando erro, poste novamente!

F
CARA, DEU CERTO!!!

Eu sabia que um apostrofo ia dar dor de cabeça para um programador, mas naum um parentese. Veio, valeu pra caramba, acho que naum ia conseguir sozinho, valeu!

Mas uma coisa, como eu to pegando texto de uma pagina gerada em html,

tem certas tags que eu tenho que tirar.

Tipo;

String m = " & eacute;  " //(é)

eu to usando depois que eu pego o html o metodo replaceAll()

eu queria fazer algo mais ou menos assim

m.replaceAll("&(.*?)acute,…);

queria fzer ele colocar o acento na letra que ele pegar no matching group, mas o mg vale para metodos assim?

mas isso é bobagem, acho q vou fzer para todos, obrigado Mandu, tu ajudou pra caramba, se eu tiver mais alguma duvida eu posto, e se precisar, estamos ae, valeu cara!
Criado 2 de agosto de 2006
Ultima resposta 3 de ago. de 2006
Respostas 9
Participantes 2