在Haskell中快速解析大型UTF-8文本文件

4

我有一个300MB的文件(链接),其中包含utf-8字符。我想编写一个Haskell程序,与以下命令等效:

cat bigfile.txt | grep "^en " | wc -l

这在我的系统上运行了2.6秒。
目前,我将文件读取为普通字符串(readFile),并拥有以下内容:
main = do
    contents <- readFile "bigfile.txt"
    putStrLn $ show $ length $ lines contents

几秒钟后我收到以下错误信息:
Dictionary.hs: bigfile.txt: hGetContents: invalid argument (Illegal byte sequence)

我猜想我需要使用一些更友好的utf-8工具?如何让它既快速又兼容utf-8?我了解到Data.ByteString.Lazy可以提高速度,但Real World Haskell说它不支持utf-8。


4
更快的方法是 grep -c "^en " bigfile.txt。无效字节序列错误意味着文件不是有效的UTF-8格式,或者您的文件句柄没有设置为UTF-8。如果您的 GHC 版本较新,它会默认以本地编码读取文件,请检查一下。如果不是UTF-8,请使用 hSetEncoding stdin utf8 来修复。 - Daniel Fischer
1个回答

7

utf8-string提供了读写UTF8字符串的支持。它重用了ByteString基础设施,因此接口很可能非常相似。

另一个与上述项目相关且同样受到ByteStrings启发的Unicode字符串项目在这篇硕士论文中讨论。


1
我觉得问这个问题很蠢,但是我该如何将文件作为惰性的UTF8字符串读取?Data.ByteString.Lazy.Char8有一个readFile方法,但是Data.ByteString.Lazy.UTF8没有。 - Sean Clark Hess
啊,你使用了Data.ByteString.Lazy.readFile,然后在ByteString上调用了Data.ByteString.Lazy.UTF8的函数。谢谢! - Sean Clark Hess
@hammar - 不行,因为它把文件读取成了一个字符串。使用Data.ByteString.Lazy.readFile就可以了。 - Sean Clark Hess
拉取请求已经提交(https://github.com/glguy/utf8-string/pull/4):通过使用这个utf8-string包,我现在可以在Haskell中获得1.2秒的速度(而上述shell脚本只需要1秒)。 - Thomas M. DuBuisson
System.IO.UTF8 包含了 readFile 等函数,但在 utf8-string-1 版本中已被移除。 - MikaelF
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接