Первая попытка парсер СВГ


Я подумал, что это о времени, чтобы прыгнуть в какой Хаскелл, так вот первая попытка специфично парсер СВГ:

import System.Environment
import Text.ParserCombinators.Parsec 

parseFile fname = parseFromFile (manyTill (try tag) (try readEnd)) fname

tag = do manyTill anyChar . try $ lookAhead tagStart
         char '<'
         name <- many $ noneOf " "
         props <- tagContents
         char '>'
         junk
         return (name, props)

tagContents = do props <- manyTill property . try . lookAhead $ char '>'
                 junk
                 return props

property = do spaces
              name <- many1 $ noneOf "="
              string "=\""
              val <- manyTill anyChar $ char '"'
              junk
              return (name, val)

junk = optional . many $ oneOf "\n\r\t\\/"

readEnd = do optional $ string "</svg>" 
             junk
             eof
tagStart = do char '<'
              tagName

tagName = string "rect" 
          <|> string "polygon" 
          <|> string "polyline" 
          <|> string "circle" 
          <|> string "path" 
          <|> string "g" 
          <|> string "svg"

Прежде чем кто-нибудь спросит, одна из целей этой программы (кроме обучения) заключается в том, что его следует признать недействительным Свгс (например, частичное SVG или одна, что была сохранена в формате RTF), поэтому я вовсю пользуешь попробовать, и выборочного теги.

Как следует из названия, это-мой первый учебник покушении на Хаскеле, так что дайте мне все указатели, что можно собрать (и выделить что-нибудь, что сигналы сломанной понимание с моей стороны).

Я также ценю советы о том, как подбирать свойства (а не только теги). Я пыталась писать собственность как

property = do manyTill anyChar . try $ lookAhead tagName
              name <- many1 $ noneOf "="
              string "=\""
              val <- manyTill anyChar $ char '"'
              junk
              return (name, val)

и определение propname-поля как

propName = string "points" 
           <|> string "x" 
           <|> string "y" 
           <|> string "r" 
           <|> string "d" 
           <|> string "cx" 
           <|> string "cy" 
           <|> string "width" 
           <|> string "height" 
           <|> string "transform"

Это выглядит как он должен работать, так как это в основном, как я получил метку прыгает к следующему нужному тегу, но это дает мне неожиданные ошибки ввода.


Редактирование Второго:

import System.Environment
import Text.ParserCombinators.Parsec 

type TagName = String
type Property = (PropName, Value)
type PropName = String
type Value = String

parseFile fname = parseFromFile (manyTill (try tag) (try readEnd)) fname

tag :: GenParser Char st (TagName, [Property])
tag = do manyTill anyChar . try $ lookAhead tagStart
         name <- tagStart
         props <- tagContents
         char '>'
         junk
         return (name, props)

tagContents :: GenParser Char st [Property]
tagContents = do props <- manyTill property . try . lookAhead $ char '>'
                 junk
                 return props

property :: GenParser Char st (PropName, Value)
property = do manyTill anyChar . try $ lookAhead propName
              name <- many1 $ noneOf "="
              string "=\""
              val <- manyTill anyChar $ char '"'
              junk
              return (name, val)

junk = many $ oneOf "\n\r\t\\/{} "

tagStart :: GenParser Char st TagName
tagStart = do char '<'
              name <- tagName
              return name

readEnd = do optional $ string "</svg>" 
             junk
             eof

tagName = oneStringOf ["rect", "polygon", "polyline", "circle", "path", "g", "svg"]
propName = oneStringOf ["points", "x", "y", "r", "d", "cx", "cy", "width", "height", "transform"]

oneStringOf :: [String] -> GenParser Char st String
oneStringOf = choice . map (try . string)
  • Добавлено попытке определения oneStringOf


894
8
задан 19 марта 2011 в 05:03 Источник Поделиться
Комментарии
1 ответ

ОК, Вот несколько вещей, которые я заметил:

В первую очередь, в то время как код, кажется, достаточно легко следовать, как это, пару комментов и там и там, конечно, не повредит.


tag = do manyTill anyChar . try $ lookAhead tagStart
char '<'
name <- many $ noneOf " "

Это кажется странным, что вы сначала использовать tagStart найти пока, где, чтобы соответствовать, но тогда не используйте его, чтобы на самом деле соответствовать тег.


junk = optional . many $ oneOf "\n\r\t\\/"

Поскольку многие уже может совпасть с пустой строкой, что делает его необязательным ничего не меняет.


tagName = string "rect" 
<|> string "polygon"
<|> string "polyline"
<|> string "circle"
<|> string "path"
<|> string "g"
<|> string "svg"

Это выглядит немного однообразной. Я бы определить вспомогательную функцию, которая совпадает с одним из списка строк:

-- Takes a list of strings and returns a Parser which matches any of those strings
oneStringOf = choice . map (try . string)

tagName = oneStringOf ["rect", "polygon", "polyline"] -- etc

При добавлении попробовать мы сделали так, что он на самом деле работает правильно Теперь (благодаря Джоуи Адамс, отметив, что исправить).


А почему ваше альтернативное определение недвижимости не работает: я не уверен, что это единственное, что держит его от работы, но одна ошибка в том, что вы написали имя тега , когда вы имели в виду propname-поля.

5
ответ дан 19 марта 2011 в 07:03 Источник Поделиться