2012-06-26 4 views
2

Я очень новичок в Haskell, и в настоящее время я пытаюсь решить проблему, требующую некоторого синтаксического анализа строк. Моя строка ввода содержит список слов с запятыми в кавычках. Я хочу проанализировать эту единственную строку в списке слов в виде строк. Где я должен начать изучать разбор такой строки? Есть ли partuclar модуль и/или функции, которые будут полезны?Анализ строк в Haskell

p.s. Пожалуйста, не публикуйте полное решение. Я просто прошу указатель на начальное место, чтобы я мог научиться этому.

+4

[SPLIT] (http://hackage.haskell.org/package/split), вероятно, будет полезно. Или вы можете использовать настоящие парсеры, такие как [parsec] (http://hackage.haskell.org/package/parsec). –

+0

Похоже, что слова разделяются запятыми * и * кавычками? –

+0

@BenMillwood Слова окружены кавычками и разделены запятыми. –

ответ

5

С String s - это просто списки Char s в Haskell, Data.List - хорошее место для начала поиска (в интересах обучения Haskell).

Для более сложных случаев (где запятые могут вставляться внутри кавычек и, например, их следует игнорировать), parsec (как упомянуто Даниилом) было бы лучшим решением.

Кроме того, если вы ищете синтаксический анализ CSVs, вы можете попробовать Text.CSV, хотя я не пробовал, поэтому не могу сказать, насколько он будет полезен.

1

В интересах получения полного ответа для тех, кто по этому вопросу, Data.Text имеет некоторые хорошие функции.

1

Используйте парсер для всего, что является «настоящей работой».

Для введения чтения https://therning.org/magnus/archives/tag/parsec

+0

Эта ссылка сейчас на http://therning.org/magnus/posts/2007-05-27-289-adventures-in-parsing.html; см. https://wiki.haskell.org/Parsec Sec. 5.2 для других ссылок в серии и дополнительных ресурсов –

3

Вот особенно дерзкий способ продолжить:

parseCommaSepQuotedWords :: String -> [String] 
parseCommaSepQuotedWords s = read ("[" ++ s ++ "]") 

Это может работать, но это очень хрупкая и довольно глупо. По сути, вы используете тот факт, что Haskell способ записи списков строк почти совпадает с вашим путем, и, следовательно, встроенный экземпляр Read - это почти вещь, которую вы хотите. Вы можете использовать reads для лучшей отчетности об ошибках, но на самом деле вы, вероятно, захотите сделать что-то еще.

В общем, parsec является действительно стоит взглянуть на - это радость для использования, и одна из вещей, которые первоначально действительно получил меня взволнованный о Haskell. Но если вы хотите получить доморощенные решения, я часто пишу простые вещи, используя операторы case на результат span и break. Предположим, что вы ищете следующую точку с запятой на входе.Тогда break (== ';') inp вернется (before, after), где:

  • before является содержание inp до (и не включая) первую точку с запятой (или все это, если его нет)
  • after является остаток строки :
    • если after не пусто, то первый элемент является точкой с запятой
    • независимо от того, что еще происходит, before ++ after == inp

Так разобрать список операторов, разделенных точкой с запятой, я мог бы сделать это:

parseStmts :: String -> Maybe [Stmt] 
parseStmts inp = case break (== ';') inp of 
    (before, _ : after) -> -- ... 
    --^before is the first statement 
    -- ^ignore the semicolon 
    --   ^after is the rest of the string 
    (_, []) -> -- inp doesn't contain any semicolons 
5

Самым мощным решением является анализатор комбинатор. Haskell имеет некоторые из них, но прежде всего, что приходит мне на ум являются:

  • parsec: очень хороший универсальный разборе библиотека
  • attoparsec: более быструю версию парсек, которая жертвует качество сообщений об ошибках и некоторые другие возможности для увеличения скорости
  • uu-parsinglib: очень мощный разборе библиотеки

большим преимуществом анализатора комбинаторов является то, что это очень легко определить с помощью парсеров do обозначение (или Applicative стиль, если хотите).

Если вы просто хотите, чтобы некоторые быстрые и простые возможности работы со строками, то обратитесь к text библиотеку (для высокопроизводительных байт-кодированных строк) или Data.List (для обычных списков, которые кодируются строк), которые обеспечивают необходимые функции для работы строки.

+0

Когда я был noob, я не мог делать головы или хвосты uu-parsinglib. Я не пробовал это с тех пор, но я бы точно не назвал это дружественным. –

3

Наконец-то я решил опрокинуть свои собственные функции синтаксического анализа, так как это такая простая ситуация. Я узнал много о Haskell, так как я первый отвечал на этот вопрос и хотим документировать мое решение здесь:

split :: Char -> String -> [String] 
split _ "" = [] 
split c s = firstWord : (split c rest) 
    where firstWord = takeWhile (/=c) s 
      rest = drop (length firstWord + 1) s 

removeChar :: Char -> String -> String 
removeChar _ [] = [] 
removeChar ch (c:cs) 
    | c == ch = removeChar ch cs 
    | otherwise = c:(removeChar ch cs) 

main = do 
    handle <- openFile "input/names.txt" ReadMode 
    contents <- hGetContents handle 
    let names = sort (map (removeChar '"') (split ',' contents)) 
    print names 
    hClose handle 
Смежные вопросы