题
为了促进我对Haskell的了解和舒适的项目,我正在努力实施JPEG解码器,该解码器将在未来的计算机视觉工作中派上用场。
我选择的第一步是在图像中解析所有“标记”。这些由字节0xFF表示,然后是non-0字节。 0xff字节然后将0x00字节视为正常数据。
我遇到的问题是,在遇到0xFF 0x00组合时,解析似乎完全完成并且找不到有效的标记(如果您在标准JPEG上运行,您将看到图像标记的开始,但没有解析的结尾,但没有图像标记通常在图像数据本身中发生0xFF 0x00。
import System.Environment
import System.IO
import Control.Applicative hiding (many)
import Data.Attoparsec as A
import qualified Data.ByteString as BS
parseMarker = do
part1 <- word8 0xFF
part2 <- notWord8 0x0
return (part1, part2)
parseSection = do
A.skipWhile (\x -> x /= 0xFF) *> parseMarker
parseBody = do
many parseSection
parseJPEG jpeg = do
handleParseResult $ feed (parse parseBody jpeg) BS.empty
handleParseResult result = do
case result of
Fail _ _ msg -> msg
Done _ r -> show r
_ -> ""
main = do
(filename : _ ) <- getArgs
handle <- openFile filename ReadMode
contents <- BS.hGetContents handle
putStrLn $ parseJPEG contents
hClose handle
解决方案
自从 parseMarker
消耗输入,但可能会失败,当您遇到0xFF 0x00时,您必须能够“倒带”并重试不同的解析。
我没有安装Attoparsec,但我认为它与Parsec相似,默认情况下不会回溯。
parseSection =
skipMany (notWord8 0xFF <|> try (word8 0xFF >> word8 0x0)) >> parseMarker
其他提示
问题是您不告诉它要解析0xff,0x00的序列,它已经很晚了,希望下一个答案器会插入单词(也许它对您有足够的帮助),但这是替代方案 parseMarker
并随附 handleParseResult
:
parseMarker = do -- or call it "parsePotentialMarker"
part1 <- word8 0xFF
part2 <- anyWord8
return $
if (part2 /= 0)
then [(part1, part2)]
else []
-- ... skipping other functions...
handleParseResult result = do
case result of
Fail _ _ msg -> msg
Done _ r -> show (concat r)
-- ...
附带说明,在问题中,在代码中进行功能齐全的测试有助于:类似:
main =
let contents = BS.pack [1,2,3,4,0xFF,1 {- marker 1 -},0xFF,0x00,0xFF,2 {- marker 2 -},31,13,0xFF,0x00]
in putStrLn $ parseJPEG contents
不隶属于 StackOverflow