【问题标题】:How to find and replace unicode chars in Haskell?如何在 Haskell 中查找和替换 unicode 字符?
【发布时间】:2017-12-17 11:14:40
【问题描述】:

我有一个 unicode 文件,其中包含 MediaText 标记中的(瑞典语)维基百科文章。我想从所有标记中清除它。在某些情况下,我想从标记标签中提取文本,例如超链接中的链接标题(如简化的wikiextractor)。

我的方法是在文件上运行一组正则表达式以删除标记。在链接示例中,我需要将[[link]] 替换为link。只要文本不包含诸如ö之类的unicode字符,我就可以使用正则表达式很好地解决此问题。

我尝试过的示例:

ghci> :m +Data.Text
ghci> subRegex (mkRegex "\\[\\[([() a-zA-Z]*)\\]\\]") "Se mer om [[Stockholm]]" "\\1"
"Se mer om Stockholm"
ghci> subRegex (mkRegex "\\[\\[([() a-zA-Z]*)\\]\\]") "Se mer om [[Göteborg]]" "\\1"
"Se mer om [[G\246teborg]]"

为什么这不起作用?如何让正则表达式引擎意识到ö 确实是一个普通字母(至少在瑞典语中)?

编辑: 问题似乎并不真正存在于模式中,而是存在于引擎中。如果我在链接文本中允许除q 之外的所有字符,则可以期望ö 被允许。但并非如此……

ghci> subRegex (mkRegex "\\[\\[([^q]*)\\]\\]") "[[Goteborg]]" "\\1"
"Goteborg"
ghci> subRegex (mkRegex "\\[\\[([^q]*)\\]\\]") "[[Göteborg]]" "\\1"
"[[G\246teborg]]"
ghci> subRegex (mkRegex "ö") "ö" "q"
"q"
ghci> subRegex (mkRegex "[ö]") "ö" "q"
"\246"

这个问题似乎是在使用字符类时特别出现的。它自己匹配öfine。

【问题讨论】:

  • 你使用什么库?当我尝试它们时,您的哥德堡正则表达式给我ReturnCode 17,"illegal byte sequence"。在任何情况下,POSIX regex spec 表示“匹配 [is] 基于用于对字符进行编码的位模式...... [I]fa 字符集包含图形符号的两个或多个编码......没有尝试搜索编码符号的任何其他表示。如果需要...指定包含...符号的所有变体的等价类。也许就是这样?
  • 我使用了regex-compat 库,它包含subRegex 函数。我的 ubuntu 上有瑞典语键盘设置。您可以看到 Haskell 已正确地将其识别为 unicode 点 246。我不希望字符类成为问题,因为否定的 char 类模式也不起作用。

标签: regex haskell unicode


【解决方案1】:

我现在决定按照作者撰写的SO Answer 中的建议使用 Text.Regex.PCRE.Heavy。它解决了我的问题。

这样,解决方案就变成了

GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help
Prelude> :m Text.Regex.PCRE.Heavy
Prelude Text.Regex.PCRE.Heavy> :set -XFlexibleContexts
Prelude Text.Regex.PCRE.Heavy> :set -XQuasiQuotes
Prelude Text.Regex.PCRE.Heavy> gsub [re|\[\[([^\]]*)\]\]|] (\(firstMatch:_) -> firstMatch :: String) "[[Göteborg]]" :: String
"G\246teborg"

不幸的是,我仍然不知道为什么 POSIX 后端不能处理这个问题,但 PCRE 后端可以。

【讨论】:

    【解决方案2】:

    要在 Haskell 中查找和替换 unicode 字符,我们可以使用 streamEdit 函数和 Megaparsec 解析器进行模式匹配(而不是正则表达式)。 Megaparsec letterChar 解析器将匹配所有瑞典字母。

    :set -XOverloadedStrings
    import Text.Megaparsec
    import Text.Megaparsec.Char
    import Replace.Megaparsec
    import Data.Text as T
    import Data.Text.IO as T
    import Data.Void
    
    let wikilink :: Parsec Void T.Text [Char]
        wikilink = do
            _ <- chunk "[["
            fst <$> manyTill_ letterChar (chunk "]]")
    
    T.putStr $ streamEdit wikilink T.pack "Se mer om [[Stockholm]]"
    T.putStr $ streamEdit wikilink T.pack "Se mer om [[Göteborg]]"
    
    Se mer om Stockholm
    Se mer om Göteborg
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-20
      • 2015-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-04
      • 2016-06-26
      • 1970-01-01
      相关资源
      最近更新 更多