2011-02-14 8 views
6

Tenga en cuenta que, posteriormente a la publicación de esta pregunta, pude obtener una solución yo mismo. Vea el final de esta pregunta para mi respuesta final.Analizando texto con datos opcionales al final


Estoy trabajando en un pequeño analizador en el momento de org-mode documentos, y en estos documentos partidas puedo tener un título, y, opcionalmente, puede consistir en una lista de etiquetas en el de la partida a:

* Heading   :foo:bar:baz: 

Tengo dificultades para escribir un analizador para esto, sin embargo. Lo siguiente es lo que estoy trabajando con, por ahora:

import Control.Applicative 
import Text.ParserCombinators.Parsec 

data Node = Node String [String] 
      deriving (Show) 

myTest = parse node "" "Some text here :tags:here:" 

node = Node <$> (many1 anyChar) <*> tags 

tags = (char ':') >> (sepEndBy1 (many1 alphaNum) (char ':')) 
    <?> "Tag list" 

Mientras mis trabajos simples analizador tags, que no funciona en el contexto de node porque todos los caracteres se utilizan hasta analizar el título del epígrafe (many1 anyChar). Además, no puedo cambiar este analizador para usar noneOf ":" porque : es válido en el título. De hecho, solo es especial si está en un taglist, al final de la línea.

¿Alguna idea de cómo puedo analizar estos datos opcionales?

Como un lado, este es mi primer proyecto real de Haskell, así que si Parsec no es ni siquiera la herramienta adecuada para el trabajo, siéntase libre de señalarlo y sugerir otras opciones.


Bien, ahora tengo una solución completa, pero es necesario refactorizarla. Las siguientes obras:

import Control.Applicative hiding (many, optional, (<|>)) 
import Control.Monad 
import Data.Char (isSpace) 
import Text.ParserCombinators.Parsec 

data Node = Node { level :: Int, keyword :: Maybe String, heading :: String, tags :: Maybe [String] } 
    deriving (Show) 

parseNode = Node <$> level <*> (optionMaybe keyword) <*> name <*> (optionMaybe tags) 
    where level = length <$> many1 (char '*') <* space 
      keyword = (try (many1 upper <* space)) 
      name = noneOf "\n" `manyTill` (eof <|> (lookAhead (try (tags *> eof)))) 
      tags = char ':' *> many1 alphaNum `sepEndBy1` char ':' 

myTest = parse parseNode "org-mode" "** Some : text here :tags: JUST KIDDING  :tags:here:" 
myTest2 = parse parseNode "org-mode" "* TODO Just a node" 
+0

¿Qué hay de analizar primero la cabecera de un iluminado y de ordenación de los datos en su estructura? – fuz

+0

Hola, no sé lo que estoy "encendida", pero todavía no veo cómo puedo analizar el encabezado e ignorar las etiquetas, sin consumir la sección de etiquetas en mi analizador – ocharles

+0

Hola @ocharles , ¿está realmente presente el analizador de modo orgánico resultante? ¿Está compartiendo el código? Empecé a profundizar un poco en Haskell, y la combinación de este aprendizaje con el cambio de modo orgánico es de alguna manera un pensamiento agradable. Saludos cordiales, –

Respuesta

1
import Control.Applicative hiding (many, optional, (<|>)) 
import Control.Monad 
import Text.ParserCombinators.Parsec 

instance Applicative (GenParser s a) where 
    pure = return 
    (<*>) = ap 

data Node = Node { name :: String, tags :: Maybe [String] } 
    deriving (Show) 

parseNode = Node <$> name <*> tags 
    where tags = optionMaybe $ optional (string " :") *> many (noneOf ":\n") `sepEndBy` (char ':') 
     name = noneOf "\n" `manyTill` try (string " :" <|> string "\n") 

myTest = parse parseNode "" "Some:text here :tags:here:" 
myTest2 = parse parseNode "" "Sometext here :tags:here:" 

Resultados:

*Main> myTest 
Right (Node {name = "Some:text here", tags = Just ["tags","here",""]}) 
*Main> myTest2 
Right (Node {name = "Sometext here", tags = Just ["tags","here",""]}) 
+0

Se ve muy bien, pero parece que no puedo cargarlo en mi GHCI: declaración de instancia ilegal para 'Applicative (GenParser sa) '. Sin embargo, puedo solucionar esto eliminando completamente la instancia de la aplicación. Sin embargo, todavía deja el problema de que "Encabezado: más texto: etiquetas: aquí:" no analiza :( – ocharles

+0

Eso se ve bien, pero ¿podría explicar qué está haciendo exactamente? –

+0

@ocharles no pegar directamente en ghci - no puede manejar ciertos bits de sintaxis. Guarda en foo.hs y luego en ghci ejecuta ": l foo". Puedes hacer que ghci recoja tus cambios luego ejecutando ": r" para actualizar. – Bill

Cuestiones relacionadas