Regexps endiabradas

A situacao eh a seguinte:

todos ja conhecem os bbcodes, essas tagzinhas entre colchetes que usamos o tempo todo aqui no forum, nao?!.. Pois bem, estava eu fazendo a implementaco delas no jforum, testando aqui e acola, quando me liguei do fato que as tags contidas dentro de uma tag code ( [code] ) nao podem ser processadas… ou seja, devem ser consideradas como texto literal, ao inves de rolar o processamento.

Mexe aqui, arruma ali e nada parece funcionar, chegando ao ponto de fazer uns hacks bisonhos que funcionam parcialmente. Fiz da seguinte maneira:

Na definicao das tags, especifiquei que, antes de fazer o replace das tags [code] e [/code] pelo respectivo codigo HTML, deveria ser feito um outro processamento, o qual faria o trabalho sujo de evitar que outras possiveis bb tags dentro da tag code fossem processadas… Logicamente nao desejo que as demais tags, que se encontram fora de [code] / [/code], sejam afetadas, o que resulta na necessidade de pegar somente o texto entre [code] e [/code]. Para tanto, usei a seguinte regex:

(?s).*[code](.*?)[/code].*

A qual aplico no conteudo desejado. Para recuperar o conteudo, uso

Matcher matcher = Pattern.compile(bb.getBeforeUseRegexp()).matcher(p.getText());

no caso, bb.getBeforeUseRegexp()) contem a regexp mostrada anteriormente. Depois uso

String contents = matcher.group(1);

para pegar o conteudo entre [code] e [/code], vindo examente o que preciso. Apos isso, faco

contents = contents.replaceAll(bb.getBeforeReplace(), "&"+ bb.getBeforeReplaceWith());

onde bb.getBeforeReplace() contem “[” e bb.getBeforeReplaceWith() contem “#91;”. Isso faz com que o caracter de abertura de colchete seja transformado no seu respectivo codigo HTML, evitando assim que as outras regexp detectem a tag. Isso funciona ok.

Feito isso, eh hora de aplicar a regexp “real”, ou seja, a que ira substituir [code] e [/code] pelas respectivas tags HTML. Para esse caso, uso a regexp

(?s)[code](.*?)[/code]

que faz o trabalho sujo como deveria…

Ou quase. Pois agora ha os problemas em si dessa implementacao:

Logicamente, matcher.group(1) nao ira resolver o caso caso eu tenha varias tags [code] na mensagem, pois somente uma das tags sera considerada.
Eu precisaria pegar e processar todos os grupos de possiveis tags “code” existentes na mensagem, aplicar o replace do caracterer de colchete e somente entao aplicar a regexp (?s)code[/code], no final de tudo…

Sem contar que essa “solucao” que fiz ate agora ta uma gambiarra soh aparentemente…

Rafael

deixe-me pensar…
ok…bom cara, vc tem q montar aquelas arvores que se usam em compiladores, nao eh?
ai vc pode estruturar as partes na arvore e trabalha dentro de uma arvore …
entendeu?

mais ou menos assim:

[doc] um texto um texto um texto um texto [code] um code, um code[/code] mais texto maix texto [code] um code, [naotroca]aaaaa[/naotroca] um code[/code] [/doc]

isso viraria uma arvore assim:

doc---txt
  |-----code---txt
  |---txt
  |---code---txt
          |----naotroca---txt
          |----txt

ai vc faz as trocas (ou nao) nos nós da árvore…dá uma olhada… nao lembro o nome dessas arvores em compiladores… creio que sejam arvores de automatos… nao fui um bom aluno de COMP.

E, se, enquanto houver tags [code] você faz esse replace…

Mas isso só iria fazer aumentar a “gambiarra” que você diz estar fazendo

Pode ser também né…
E no seu XML de config vc definiria:

<tag> <name>code> <Replace-Inner-Tags>false</Replace-Inner-Tags> ... </tag>

E, se, enquanto houver tags [code] você faz esse replace…

Mas isso só iria fazer aumentar a “gambiarra” que você diz estar fazendo[/quote]

Nao resolve, pois a regexp nao pega todos os code de uma unica vez, e ficar rodando ela de novo ficaria retornando sempre o mesmo pecado de codigo… :?

Uma possivel solucao seria eu processar uma parte, fazer o replace pelo html, entao reprocessar desde o inicio, verificar se teve match, fazer replace pelo html, preproecessar…

Mas se tiver que chegar nesse ponto, faco manipulacao de strings no braco.

Rafael

Ceeerto, é realmente isso é muito sujo…

Você chegou a dar uma olhada na implementação dessa funcionalidade no phpBB ? Ou lá é com gambiarra também?

Bom, achei uma solucao usando a implementacao atual, e vai ficar assim ate algo melhor aparecer :wink:

Basicamente, coloquei o processamento em um while() e mudei os replaceAll() por replaceFirst()… ou seja, processo um pedaco, entao faco o match de novo, reprocesso etc etc…

tipo:

boolean keepGoing = true;

while (keepGoing) {
	Matcher matcher = Pattern.compile(bb.getBeforeUseRegexp()).matcher(p.getText());
	keepGoing = matcher.matches();
	
	if (!keepGoing) {
		break;
	}

	String contents = matcher.group(1);
	contents = contents.replaceAll(bb.getBeforeReplace(), "&"+ bb.getBeforeReplaceWith());
	
	p.setText(p.getText().replaceFirst("\Q"+ matcher.group(1) +"\E", contents));
	p.setText(p.getText().replaceFirst(bb.getRegex(), bb.getReplace()));
}					}

Funcionando esta… :shock:

Rafael

[quote=“Vegetto”]Ceeerto, é realmente isso é muito sujo…

Você chegou a dar uma olhada na implementação dessa funcionalidade no phpBB ? Ou lá é com gambiarra também?[/quote]

O que eu faco com 30 linhas de codigo, o phpbb faz com 500 … eh q no phpbb eles usam um minimo de regexp, e fazem trocentas verificacoes e manipulacoes no braco a mais…

Rafael

Pultz, que droga, não sabia que o código deles era tão porquinho

Porco eh o codigo do Nuke On JBoss… eh de dar vontade de vomitar.

O codigo do phpbb nao eh porco, os caras program direitinho. Mas devido a algumas escolhas deles em relacao a arquitetura, seguranca, e mesmo por causa de como algumas coias sao feitas em php ( nao estou dizendo que seja ruim ), o codigo eh maior… Codigo menor nao significa necessariamente codigo melhor :wink:

Rafael

Mas de 500 pra 30 linhas? Concluímos que…

haahahahhaah

abraços