Nano Hash - криптовалюты, майнинг, программирование

Неожиданный конец ввода в парсеках

Я хочу разобрать файл следующим образом:

66:3 3:4
329:2 
101:3 
495:4 
55:5 
268:5 
267:2 
242:4 
262:1 
861:1 

Мой код выглядит следующим образом:

getTestData :: String -> IO [[(Int, Int)]]
getTestData name = do
    --res <- parseFromFile testData (name ++ ".test")
    fc <- readFile (name ++ ".test")
    let res = parse testData "test data" fc
    case res of
        Left e -> error $ show e-- "test data parse eror."
        Right ts -> return ts

eol = char '\n'
testData = endBy line eol
--testData = many line
testTuple = do
    i <- natural
    colon
    r <- natural
    return (fromIntegral i:: Int, fromIntegral r:: Int)

line = sepBy testTuple whiteSpace

Но при запуске выдает исключение:

ts <- getTestData "data" 
*** Exception: "test data" (line 11, column 1):
unexpected end of input
expecting natural or "\n"

Я не понимаю, почему он сказал строку 11, когда в моем файле data.test всего 10 строк. Поэтому мне не удалось решить эту проблему после нескольких попыток.

04.06.2011

  • Вы находите конец файла, а не конец строки. Также обратите внимание, что комбинатор Parsec по умолчанию whiteSpace, используемый в синтаксическом анализаторе line, потребляет новые строки, поэтому вы не хотите, чтобы testData использовал eol в качестве условия endBy. Возможно, использование testData = many1 line сработает, но в целом вы должны быть очень осторожны с обработкой пробелов даже для простых форматов. Parsec был создан для синтаксического анализа языков программирования, а не файлов данных, ориентированных на строки, поэтому он видит все пробелы как одно и то же, а не различает символы новой строки или что-то еще. 04.06.2011
  • при использовании many он жалуется так: *** Exception: Text.ParserCombinators.Parsec.Prim.many: комбинатор 'many' применяется к синтаксическому анализатору, который принимает пустую строку. 04.06.2011
  • Что, если вы превратите line в line = sepBy1 testTuple whiteSpace? (хотя это идет по изворотливой дорожке в отношении пробелов) 04.06.2011
  • Переход на sep1 приводит к той же проблеме. И я не думаю, что это связано с исключением. Интересно, виновата ли строка 11, где в моем файле всего 10 строк. 04.06.2011
  • На самом деле я ошибся, предложив line = sepBy1 testTuple whiteSpace - вы не можете написать линейно-ориентированный синтаксический анализатор, используя whiteSpace. В этом случае, поскольку вам нужен синтаксический анализатор, ориентированный на строки, а ваш формат в остальном прост, вам лучше создавать примитивные синтаксические анализаторы с Text.ParserCombinators.Parsec.Char, а не использовать синтаксические анализаторы токенов из Text.ParserCombinators.Parsec.Token. Однако вам нужно будет написать свою собственную версию natural. 04.06.2011
  • Я изменил whiteSpace на many (char ' '), но это не помогло. 04.06.2011
  • Это не поможет - проблема в том, что natural и colon потребляют все завершающие пробелы, поэтому синтаксический анализатор testTuple уже использовал все символы новой строки. Для синтаксического анализатора, чувствительного к пробелам, вам необходимо реализовать свои собственные версии синтаксических анализаторов в Text.Parsec.Token. 04.06.2011

Ответы:


1

Я думаю, что whiteSpace в line потребляет новые строки. Таким образом, весь ваш файл анализируется одним парсером line, а парсеру eol никогда не достанется парсер "\n". Попробуйте заменить whiteSpace на many (char ' ') и посмотрите, поможет ли это.

04.06.2011
  • При изменении whiteSpace на many (char ' ') возникает похожее исключение: *** Исключение: тестовые данные (строка 11, столбец 1): ожидаемый конец ввода, естественный или \n 04.06.2011
  • Я предполагаю, что синтаксический анализатор находит eof в строке 11, чтобы считать это неожиданным. 04.06.2011

  • 2

    Это рабочая реализация, использующая примитивные синтаксические анализаторы символов, а не синтаксические анализаторы токенов. Примечание. Надежнее не использовать пробел в качестве разделителя, а удалить его, если он существует. Биты, где я использовал однострочную нотацию, будут намного аккуратнее, если вы используете (<*) из Applicative.

    {-# OPTIONS -Wall #-}
    
    module ParsecWhite where
    
    import Text.ParserCombinators.Parsec
    
    import Data.Char
    
    main = getTestData "sample"
    
    getTestData :: String -> IO [[(Int, Int)]]
    getTestData name = do
        --res <- parseFromFile testData (name ++ ".test")
        fc <- readFile (name ++ ".test")
        let res = parse testData "test data" fc
        case res of
            Left e -> error $ show e -- "test data parse eror."
            Right ts -> return ts
    
    testData :: Parser [[(Int,Int)]]
    testData = input
    
    
    input :: Parser [[(Int,Int)]]
    input = many (do { a <- line; newline; return a })
         <?> "input"
    
    line :: Parser [(Int,Int)]
    line = many (do { a <- testTuple; softWhite; return a})  <?> "line"
    
    testTuple :: Parser (Int,Int)
    testTuple = do
        i <- natural
        colon
        r <- natural
        return (i,r)
      <?> "testTuple"
    
    softWhite :: Parser ()
    softWhite = many (oneOf " \t") >> return ()
    
    colon :: Parser () 
    colon = char ':' >> return ()
    
    natural :: Parser Int
    natural = fmap (post 0) $ many1 digit
      where
        post ac []     = (ac * 10) 
        post ac [x]    = (ac * 10) + digitToInt x
        post ac (x:xs) = post ((ac * 10) + digitToInt x) xs
    
    04.06.2011
  • Спасибо за Ваш ответ. Это работает хорошо. Я переписал свой код в соответствии с вашим и действительно обнаружил, что все естественные пробелы и строки в моем исходном коде должны быть изменены на ваши, чтобы он работал. 04.06.2011
  • Я также выясняю, почему мое первоначальное определение «линии» не сработало. Поскольку в моем тестовом файле есть пробелы в конце, синтаксический анализатор предполагает, что будут и другие кортежи. 04.06.2011

  • 3

    Бьюсь об заклад, вам не хватает новой строки в конце последней строки. Для синтаксического анализа полной строки это должно быть "861:1\n", но, вероятно, это "861:1EOF". Поэтому я думаю, что ваш парсер правильно идентифицирует ваш ввод как неправильный.

    04.06.2011
  • *Main› readFile data.test 66:3 3:4\n329:2 \n101:3 \n495:4 \n55:5 \n268:5 \n267:2 \n242:4 \n262:1 \n861:1 \ n Значит, это не так. 04.06.2011

  • 4

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

    col (== 1) "only matches beginning of line"
    
    col pred errStr = do
      c <- sourceColumn <$> getPosition
      if pred c then return ()
                else unexpected errStr
    
    04.10.2013
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..