2010-01-18 3 views
1

J'ai une base de données pleine de messages à partir d'un tableau d'affichage. Le conseil utilise des codes BB comme style de formatage. À savoir:Parse entrée utilisateur arbitraire

  • Je ne suis pas formaté
  • Ceci est [b] gras [/ b] Texte
  • Les balises peuvent aussi [i] [b] être [/ b] emboîtés [/ i]
  • Et le [b] imbrication [i] peut être [/ b] plutôt [/ i] laid

Mon but ultime est de convertir ces messages dans une certaine XML bien formé (pas de discussion ici;)). Je ne veux pas utiliser l'expression régulière, qui échouera à un moment donné (en fait: c'est le cas).

Première étape: analyser un message dans une sorte de représentation interne (un graphique, un arbre, etc.). Et je suis coincé à ce stade. L'extraction réelle n'est pas un gros problème, mais le stockage est. Comment est-ce que je représente ce type de balisage dans une structure significative.? Mon problème semble être similaire (ou presque identique) à un navigateur construisant un DOM à partir d'un fichier HTML. Donc je pense qu'il y a des stratégies pour le résoudre. Je sais que la solution ne sera pas parfaite mais je suis prêt à investir beaucoup de temps pour construire le meilleur possible.

Question: Avez-vous des conseils/indices/commentaires? Des articles ou du papier que vous pouvez recommander? Ou un livre qui traite de ces sujets? Je suis reconnaissant pour toute contribution.

Répondre

2
Et le [b] imbrication [i] peut être [/ b] plutôt [/ i] laid

J'ai écrit un analyseur très similaire à ce que vous cherchez à faire, sauf que ce serait lancer une erreur sur votre quatrième exemple. Quelque chose à l'effet de "balise de fin inattendue [/ b] dans [i]".

Je pense que ce que vous voulez faire est très faisable, mais en interne, vous souhaitez créer un arbre comme si votre texte original:

"And the [b]nesting [i]can be[/i][/b][i] rather[/i] ugly". (Je ne pense pas que ce serait nécessaire si vous n'aviez pas besoin de le convertir en XML plus tard.) S'il n'y avait pas besoin de convertir en XML, vous pourriez garder une liste chaînée de sections de texte où chaque section est marquée avec sa combinaison de format Deux approches possibles à ce problème viennent à l'esprit (bien sûr, il pourrait y avoir de meilleures possibilités). 1) Pré-traiter et insérer l'extrémité manquante et commencer les étiquettes si nécessaire. 2) Construisez votre arbre d'analyse et où il y a chevauchement des balises impliquent les balises manquantes basées sur le contexte actuel. Je pense que le numéro d'approche (2) serait plus simple et plus propre.

Vous pouvez modéliser votre arborescence en fonction d'un modèle composite dans lequel vous avez une classe AbstractElement, une classe TextElement qui étend AbstractElement et une classe Tag qui étend AbstractElement et contient une liste de sous-éléments de type AbstractElement.

Vous commencerez par créer une instance de Tag racine. Vous appelez ensuite rootTag.parse (texte). Vous auriez besoin d'un scanner qui pourrait renvoyer 3 types de jetons: le texte, les balises de début et les balises de fin. Le scanner vous permettrait d'y insérer des jetons, qu'il retournerait avant tout jeton scanné normal. Cela vous permet d'envoyer de nouveaux jetons de balise de début après avoir rencontré et traité la balise de fin inattendue. Vous devez également savoir quand vous avez terminé avec l'entrée. Je vais utiliser un 4ème type de jeton pour ça.

 
    /* methods within class Tag */ 
    public void parse(String text) { 
     MyScanner scanner = new MyScanner(text); 
     parse(scanner); 
    } 

    /* returns next token */ 
    private Token parse(MyScanner scanner) { 
     Token firstToken = scanner.getNextToken(); 
     return parse(scanner,firstToken); 
    } 

    private Token parse(MyScanner scanner) { 
     Token firstToken = scanner.getNextToken(); 
     return parse(scanner,firstToken); 
    } 

    private Token parse(MyScanner scanner, Token token) { 
     while (!token.isDone() && !token.isEndTag()) { 
      if (token.isStartTag()) { 
       Tag subTag = new Tag(token.getValue()); 
       token = scanner.getNextToken(); 
       token = subTag.parse(scanner,token); 
       addElement(subTag); 
      } 

      else { 
       TextElement text = new TextElement(token.getValue()); 
       addElement(text); 
       token = scanner.getNextToken(); 
      } 
     } 

     if (token.isEndTag()) { 
      if (!token.getValue().equals(getName()) { 
       scanner.push(new Token(Token.START_TAG,token.getValue())); 
      } 
      else { 
       token = scanner.getNextToken(); 
      } 
     } 

     return token; 
    } 

Donc, si vous deviez analyser "Et le [b] imbrication [i] peut être [/ b] plutôt [/ i] laid", ce qui suit devrait obtenir créé.

 
rootTag.parse should be adding: 
    TextElement: "And the " 
    Tag: "b" 
      TextElement: "nesting " 
      Tag: "i" 
        TextElement: "can be" 
        (... at this point the odd [/b] is encountered ...) 
        (... push "i" start tag on the scanner ...) 
      (... here the [/b] is encountered (again) ...) 
    Tag: "i" (this was scanned because it had been pushed to the scanner) 
      TextElement: " rather" 
    TextElement: " ugly" 

Note: codage dans une zone de texte ne se prête pas à des tests et le débogage. Acceptez cette réponse comme un indice ou une possibilité, pas comme votre réponse définitive.

+0

Wow. Merci beaucoup. Votre code d'exemple a résolu presque tous mes problèmes :) –

+0

Merci et bonne chance. Je viens de corriger une faute de frappe et je passais le mauvais paramètre dans l'appel push, qui est corrigé maintenant aussi. – rayd09

Questions connexes