2016-08-29 3 views
1

, чтобы узнать немного больше о Haskell (особенно Monads). Я пытаюсь создать проверку орфографии. Моя цель - пройти через документ LaTeX и сделать что-то на словах, которые не входят в список словарей.haskell parser с проверкой орфографии

Я уже написал синтаксический анализатор (строка для АСТ), код которого я вставляю ниже. Он в основном возвращает источник LaTeX, размещенный в соответствующих фрагментах (текст, формулы, команды и т. Д.). Я хотел бы знать, как создать такую ​​программу, чтобы на каждом слове, не найденном в списке, мы спрашиваем у пользователя, какое слово заменить.

(То, что мы действительно заботимся о LaTeX является то, что у нас есть некоторая часть исходного кода, которые являются текст и должны быть проверки правописания, и другие части, которые являются формулы, а не простой английский)


Пусть мне объяснить это более ясно с некоторыми примерами желаемого поведения (для простоты формулы между $ HERE IS THE FORMULA $)

Источник:

This is my frst file and here 
we have a formula: $\forall x \quad x$ 

Desir изд поведение:

In file 'first.tex' at line 1: 'frst' unknown 
1 This is my **frst** file and here 
2 we have a formula: $\forall x \quad x$ 
Action [Add word to dictionary/Change word]? 

Основная проблема, после того как я разобран файл, я осталась с AST и не имею больше ссылок на линию, так что я не мог показать им, как выше пример.


Код для синтаксического анализатора:

import System.Environment 
import Text.Parsec (ParseError) 
import Text.Parsec.String (Parser, parseFromFile) 
import Text.Parsec.String.Parsec (try) 
import Text.Parsec.String.Char (oneOf, char, digit, string, letter, satisfy, noneOf, anyChar) 
import Text.Parsec.String.Combinator (many1, choice, chainl1, between, count, option, optionMaybe, optional, manyTill, eof, lookAhead) 
import Control.Applicative ((<$>), (<*>), (<*), (*>), (<|>), many, (<$)) 
import Control.Monad (void, ap, mzero) 
import Data.Char (isLetter, isDigit) 
import FunctionsAndTypesForParsing 

data TexFile = Items [TexTerm] 
       deriving (Eq, Show) 

data TexTerm = Comment String 
      | Formula String 
      | Command String [TexFile] 
      | Text String 
      | Block TexFile 
       deriving (Eq, Show) 

-- We get the AST as output                                   
texFile :: Parser TexFile 
texFile = Items <$> (many texTerm) <* (optional (try $ eof)) 

texTerm :: Parser TexTerm 
texTerm = lexeme $ (try comment <|> text <|> formula <|> command <|> block) 

whitespace :: Parser() 
whitespace = void $ try $ oneOf " \n\t" 

lexeme :: Parser a -> Parser a 
lexeme p = p <* (many $ whitespace) 

comment :: Parser TexTerm 
comment = Comment <$> between (string "%") (string "\n") (many $ noneOf "\n") 

formula :: Parser TexTerm 
formula = Formula <$> (try singledollar <|> doubledollar <|> equation <|> align) 
    where 
    singledollar = between (string "$") (string "$") (many1 $ noneOf "$") 
    doubledollar = between (string "$$") (string "$$") (many1 $ noneOf "$$") 
    equation = try $ between (try $ string "\\begin{equation}") (string "\\end{equation}") (manyTill anyChar (lookAhead $ try $ string "\\end{equation}")) 
    align = try $ between (try $ string "\\begin{align*}") (string "\\end{align*}") (manyTill anyChar (lookAhead $ try $ string "\\end{align*}")) 

command :: Parser TexTerm 
command = Command <$> com <*> (many arg) 
    where 
    com = char '\\' *> (manyTill (try letter <|> oneOf "*") (lookAhead $ try $ oneOf "[{ \\\n\t")) 
    arg = (try (between (string "{") (string "}") texFile) 
      <|> (between (string "[") (string "]") texFile) 
     ) 

text :: Parser TexTerm 
text = Text <$> many1 textualchars 
    where 
    textualchars = try letter <|> digit <|> oneOf " \n\t\r,.*:;-<>#@()`_!'?" 

block :: Parser TexTerm 
block = Block <$> between (string "{") (string "}") texFile 

ответ

2

Вы можете использовать getPosition действие парсек, чтобы получить текущую позицию во входном потоке. Вы можете хранить его в типе AST (т.е. изменить его на что-то вроде

data TexFile = Items [(SourcePos, TexTerm)] 

)

+0

Принимается, потому что он лучше подходит для того, что я уже сделал. Когда у меня будет больше времени, я также проверю megaparsec, как советует другой ответ – trenta3

1

Ваша основная проблема заключается в том, что вы выбрасывая информация о белое пространство в файле. Если вы записали пробел в качестве другого TexTerm , вы могли бы a) восстановить содержимое файла из TexFile и b) знать , в какой строке отображается каждый TexTerm.

Так один подход заключается в добавлении WhiteSpace конструктора TexTerm:

data TexTerm = Comment String 
      | ... 
      | WhiteSpace String 

Теперь, как вы пройти свой AST вы можете определить, какая линию каждой конструкция на пути подсчета количества символов новой строки в каждом WhiteSpace конструктора.

Однако это будет усложнять ваш синтаксический анализатор, поскольку вы пропускаете пробел, используя lexeme. Если все, что вам нужно сделать, это орфографии документ TeX, Я хотел бы предложить «тег-суп» подход с использованием более простых структур данных:

type TexFile = [TexTerm] 

data TeXTerm = Comment String 
      | Formula String 
      | Command String  -- e.g. \someCommand 
      | Text String 
      | Sym String   -- e.g. Sym "{" or Sym "}" 
      | WhiteSpace String -- e.g. WhiteSpace "\n" 

Обратите внимание, что TeXFile и TexTerm плоские - нерекурсивна - структуры данных. Мы просто обозначаем вход TeX.

Смежные вопросы