Haskell:如何检查字符是否有效utf8

Haskell:如何检查字符是否有效utf8,haskell,utf-8,Haskell,Utf 8,如何检查haskell中的字符是否是有效的UTF8码点 我有一个生成字符串的类,它受一些约束集的约束,还有一个该类的任意实例,它只生成满足这些约束的字符串。我用的是GenValidity。但是字符串的标准生成器偶尔会生成无效字符;例如“\x”。毫不奇怪,这会在以后引发问题 “无效”是指Data.Text.Encoding.streamDecodeUtf8标记错误: λ> streamDecodeUtf8 (Data.ByteString.Char8.pack "\xed") Some ""

如何检查haskell中的字符是否是有效的UTF8码点

我有一个生成字符串的类,它受一些约束集的约束,还有一个该类的任意实例,它只生成满足这些约束的字符串。我用的是GenValidity。但是字符串的标准生成器偶尔会生成无效字符;例如“\x”。毫不奇怪,这会在以后引发问题

“无效”是指Data.Text.Encoding.streamDecodeUtf8标记错误:

λ> streamDecodeUtf8 (Data.ByteString.Char8.pack "\xed")
Some "" "\237" _
λ> streamDecodeUtf8 (Data.ByteString.Char8.pack "\xed")
Some "" "\237" _
我想给我的GenValidity实例添加一个约束,该约束基于一个假设的isValidUTF8::Char->Bool函数,但令人惊讶的是,我找不到任何匹配的约束。我能做的最好的事情是

((\ (Data.Text.Encoding.Some _ x _) -> x /= "") . Data.Text.Encoding.streamDecodeUtf8With (\ _ _ -> Nothing) . Data.ByteString.Char8.pack) . pure
这肯定是相当重的,我担心转换到ByteString,然后转换到文本,可能会引入尖锐的边缘

我很惊讶,我找不到更好的/预罐装的


欢迎咨询和指点

这些例子的效果与预期一致

如何检查字符是否有效UTF-8的问题毫无意义,但不能因为不知道自己不知道的内容而受到指责。这是基于对UTF-8的误解。UTF-8是一种编码:它描述了一种将这些代码点转换为字节的方法,这些字节可以通过网络存储或发送

打个比方,这就像询问如何检查一个整数以10为基数是否有效。想想为什么这毫无意义

编码是具体数据的属性,如字节的ByteString序列,这是Haskell中的ByteString类型。一旦这些字节被解码,我们就只有文本,UTF-8不再是编码点字符抽象序列的相关概念,这是Haskell中的文本或字符串

但是字符串的标准生成器偶尔会生成无效字符;例如“\x”

所有字符都是有效的[1]Unicode代码点。”\“x”是代码点编号237

[1] :有关有效的。。。Unicode隐藏了很多复杂性

“无效”是指Data.Text.Encoding.streamDecodeUtf8标记错误:

λ> streamDecodeUtf8 (Data.ByteString.Char8.pack "\xed")
Some "" "\237" _
λ> streamDecodeUtf8 (Data.ByteString.Char8.pack "\xed")
Some "" "\237" _
streamDecodeUtf8旨在通过测试环应用于UTF-8,但Data.ByteString.Char8.pack不会生成UTF-8。pack更像是一种模仿bytestring文本的黑客;它滥用Unicode来解决Haskell中只有Unicode字符串的文本这一事实。但是这里您不想生成任意字节,所以不要使用Char8.pack

要对文本进行编码,请使用以下选项之一。正如我们所看到的,不同的编码有不同的函数,这进一步说明了上述观点,即编码不是文本固有的属性,而是与ByteString公开的内存中的表示有关

我很惊讶,我找不到更好的/预罐装的


关于Haskell中的文本和一般编程有很多抱怨,但在本例中,这个问题源于对Unicode的误解。故障不在您身上,如果您还不熟悉此系统,则此系统肯定不明显。

我不确定是否理解此要求。UTF8只是Unicode的字节格式之一。Haskell字符对象是Unicode点。字符串生成器完全有权包含一个数字代码为0xED=237的字符,即“i”。您可能想尝试在ghci:GHC.Unicode.isPrint$chr237和putStrLn$chr 237下进行评估:当然,在Unicode禁止范围的开始处,isPrint$chr 55296返回False。老实说,我不确定我从哪里得到“\x”—这是大脑衰退。应该是“\xda65”。虽然我也不再确定这是一个无效的字符。当然,我不满意的例子fn并没有将其标记为无效。事实上,我找到了它,并修改了问题以匹配它。根本的问题是Data.Text.Encoding.streamDecodeUtf8,它似乎认为“\x”是错误的。就UTF-8而言,\x是一个不完整的序列。您不能生成任意字节序列并希望它是有效的UTF-8字符串。如果在生产者端出现问题,那么在消费者端剔除无效字符串可能会花费很长时间;最好修复producer.Expression isPrint$chr read 0xda65返回False,这在无效的D800-DFFF范围内。您可能需要在Char/String级别过滤生成器的产品。谢谢@Li yao Xia。我很尴尬,我真的应该知道大部分,但我很感谢提醒和非常清楚的解释,因为我已经忘记了一些细节,并得到了它在我的脖子上。你说的很有道理,事实上,我试图从随机字节生成有效字符串;当我们后退一步时,这确实是胡说八道。我很高兴我问了,这节省了我大量的时间和麻烦试图解决错误的问题。