取消跳过HTML实体(包括命名实体)
这个问题类似于前面关于堆栈溢出的问题但是,公认的答案并没有解决命名HTML实体的问题,例如取消跳过HTML实体(包括命名实体),html,string,haskell,Html,String,Haskell,这个问题类似于前面关于堆栈溢出的问题但是,公认的答案并没有解决命名HTML实体的问题,例如ä用于字符ä因此它无法取消所有HTML的扫描 我有一些传统的HTML,它使用命名的HTML实体来表示非ASCII字符。也就是说,ö而不是ö,ä而不是ä等等。可以在维基百科上找到 我想以一种快速有效的方式将这些HTML实体转换成它们的字符等价物 我在Python 3中使用正则表达式编写了这样的代码: import re import html.entities s = re.sub
ä代码>用于字符ä
因此它无法取消所有HTML的扫描
我有一些传统的HTML,它使用命名的HTML实体来表示非ASCII字符。也就是说,ö
而不是ö
,ä
而不是ä
等等。可以在维基百科上找到
我想以一种快速有效的方式将这些HTML实体转换成它们的字符等价物
我在Python 3中使用正则表达式编写了这样的代码:
import re
import html.entities
s = re.sub(r'&(\w+?);', lambda m: chr(html.entities.name2codepoint[m.group(1)]), s)
然而,正则表达式在Haskell中似乎不是很流行、很快或很容易使用
Text.HTML.TagSoup.Entity
(TagSoup)有一个有用的表和函数,用于映射命名实体tpo代码点。使用这个和regex tdfa包,我在Haskell中创造了一个非常慢的等价物:
{-# LANGUAGE OverloadedStrings #-}
import Data.ByteString.Lazy.Char8 as L
import Data.ByteString.Lazy.UTF8 as UTF8
import Text.HTML.TagSoup.Entity (lookupEntity)
import Text.Regex.TDFA ((=~~))
unescapeEntites :: L.ByteString -> L.ByteString
unescapeEntites = regexReplaceBy "&#?[[:alnum:]]+;" $ lookupMatch
where
lookupMatch m =
case lookupEntity (L.unpack . L.tail . L.init $ m) of
Nothing -> m
Just x -> UTF8.fromString [x]
-- regex replace taken from http://mutelight.org/articles/generating-a-permalink-slug-in-haskell
regexReplaceBy :: L.ByteString -> (L.ByteString -> L.ByteString) -> L.ByteString -> L.ByteString
regexReplaceBy regex f text = go text []
where
go str res =
if L.null str
then L.concat . reverse $ res
else
case (str =~~ regex) :: Maybe (L.ByteString, L.ByteString, L.ByteString) of
Nothing -> L.concat . reverse $ (str : res)
Just (bef, match , aft) -> go aft (f match : bef : res)
unescapeEntities
函数的运行速度比上面的Python版本慢几个数量级。Python代码可以在7秒内转换大约130MB,而我的Haskell版本可以运行几分钟
我正在寻找一个更好的解决方案,主要是在速度方面。但是,如果可能的话,我也希望避免使用正则表达式(速度和避免正则表达式似乎在Haskell中是齐头并进的)。您可以安装web编码包,获取decodeHtml函数的源代码并添加所需的字符(对我来说很有用)。这就是您所需要的:
import Data.Maybe
import qualified Web.Encodings.StringLike as SL
import Web.Encodings.StringLike (StringLike)
import Data.Char (ord)
-- | Decode HTML-encoded content into plain content.
--
-- Note: this does not support all HTML entities available. It also swallows
-- all failures.
decodeHtml :: StringLike s => s -> s
decodeHtml s = case SL.uncons s of
Nothing -> SL.empty
Just ('&', xs) -> fromMaybe ('&' `SL.cons` decodeHtml xs) $ do
(before, after) <- SL.breakCharMaybe ';' xs
c <- case SL.unpack before of -- this are small enough that unpack is ok
"lt" -> return '<'
"gt" -> return '>'
"amp" -> return '&'
"quot" -> return '"'
'#' : 'x' : hex -> readHexChar hex
'#' : 'X' : hex -> readHexChar hex
'#' : dec -> readDecChar dec
_ -> Nothing -- just to shut up a warning
return $ c `SL.cons` decodeHtml after
Just (x, xs) -> x `SL.cons` decodeHtml xs
readHexChar :: String -> Maybe Char
readHexChar s = helper 0 s where
helper i "" = return $ toEnum i
helper i (c:cs) = do
c' <- hexVal c
helper (i * 16 + c') cs
hexVal :: Char -> Maybe Int
hexVal c
| '0' <= c && c <= '9' = Just $ ord c - ord '0'
| 'A' <= c && c <= 'F' = Just $ ord c - ord 'A' + 10
| 'a' <= c && c <= 'f' = Just $ ord c - ord 'a' + 10
| otherwise = Nothing
readDecChar :: String -> Maybe Char
readDecChar s = do
case reads s of
(i, _):_ -> Just $ toEnum (i :: Int)
_ -> Nothing
导入数据。可能吧
将符合条件的Web.Encodings.StringLike导入为SL
导入Web.Encodings.StringLike(StringLike)
导入数据字符(ord)
--|将HTML编码的内容解码为普通内容。
--
--注意:这并不支持所有可用的HTML实体。它也能吞咽
--所有的失败。
解码HTML::StringLike s=>s->s
解码HTML s=案例SL.UNCON s of
无->SL.empty
Just('&',xs)->fromMaybe('&'`SL.cons`decode html xs)$do
(之前、之后)返回'>'
“amp”->返回“&”
“quot“->返回”
“#”:“x”:十六进制->读取十六进制字符十六进制
“#”:“X”:十六进制->读取十六进制字符十六进制
“#”:dec->readDecChar dec
_->没什么--只是为了停止警告
之后返回$c`SL.cons`decodeHtml
只需(x,xs)->x`SL.cons`decodeHTMLxs
readHexChar::String->Maybe Char
readHexChar s=helper 0 s其中
helper i”“=返回$toEnum i
助手i(c:cs)=do
c'您可以安装web编码软件包,获取decodeHtml函数的源代码并添加所需的字符(适用于我)。这就是您所需的全部:
import Data.Maybe
import qualified Web.Encodings.StringLike as SL
import Web.Encodings.StringLike (StringLike)
import Data.Char (ord)
-- | Decode HTML-encoded content into plain content.
--
-- Note: this does not support all HTML entities available. It also swallows
-- all failures.
decodeHtml :: StringLike s => s -> s
decodeHtml s = case SL.uncons s of
Nothing -> SL.empty
Just ('&', xs) -> fromMaybe ('&' `SL.cons` decodeHtml xs) $ do
(before, after) <- SL.breakCharMaybe ';' xs
c <- case SL.unpack before of -- this are small enough that unpack is ok
"lt" -> return '<'
"gt" -> return '>'
"amp" -> return '&'
"quot" -> return '"'
'#' : 'x' : hex -> readHexChar hex
'#' : 'X' : hex -> readHexChar hex
'#' : dec -> readDecChar dec
_ -> Nothing -- just to shut up a warning
return $ c `SL.cons` decodeHtml after
Just (x, xs) -> x `SL.cons` decodeHtml xs
readHexChar :: String -> Maybe Char
readHexChar s = helper 0 s where
helper i "" = return $ toEnum i
helper i (c:cs) = do
c' <- hexVal c
helper (i * 16 + c') cs
hexVal :: Char -> Maybe Int
hexVal c
| '0' <= c && c <= '9' = Just $ ord c - ord '0'
| 'A' <= c && c <= 'F' = Just $ ord c - ord 'A' + 10
| 'a' <= c && c <= 'f' = Just $ ord c - ord 'a' + 10
| otherwise = Nothing
readDecChar :: String -> Maybe Char
readDecChar s = do
case reads s of
(i, _):_ -> Just $ toEnum (i :: Int)
_ -> Nothing
导入数据。可能吧
将符合条件的Web.Encodings.StringLike导入为SL
导入Web.Encodings.StringLike(StringLike)
导入数据字符(ord)
--|将HTML编码的内容解码为普通内容。
--
--注意:这不支持所有可用的HTML实体。它还吞咽
--所有的失败。
解码HTML::StringLike s=>s->s
解码HTML s=案例SL.UNCON s of
无->SL.empty
Just('&',xs)->fromMaybe('&'`SL.cons`decode html xs)$do
(之前、之后)返回'>'
“amp”->返回“&”
“quot“->返回”
“#”:“x”:十六进制->读取十六进制字符十六进制
“#”:“X”:十六进制->读取十六进制字符十六进制
“#”:dec->readDecChar dec
_->没什么--只是为了停止警告
之后返回$c`SL.cons`decodeHtml
只需(x,xs)->x`SL.cons`decodeHTMLxs
readHexChar::String->Maybe Char
readHexChar s=helper 0 s其中
helper i”“=返回$toEnum i
助手i(c:cs)=do
这是我的版本。它使用String(而不是ByteString)
我猜它更快,因为它不使用昂贵的正则表达式操作。我还没有测试过。如果需要更快的速度,您可以将其调整为ByteString或Data.Text。这是我的版本。它使用String(而不是ByteString)
我猜它更快,因为它不使用昂贵的正则表达式操作。我还没有测试过。您可以将其调整为ByteString或Data.Text(如果您需要更快的话)。现在还不清楚您的实际问题是什么。你在寻找更好的解决方案吗?需要帮助改进当前版本吗?如果问题不清楚,请道歉。是的,我想要一个更好的解决方案,因为我的是1。太慢了。使用的正则表达式似乎不是Haskell惯用的(因为关于它们的信息很少)。我的解决方案主要是作为一个“这就是我到目前为止得到的”出发点给出的。我对激进的想法持开放态度。你怎么看这份文件?如果我使用main=Data.ByteString.interactive unescapeEntites
并使用time cat big.txt |/regex>/dev/null
我可以获得143M big.txt的30秒时间(这是Tagsoop中列出的所有实体,中间有很多“a”)。从所有这些间接的过程中仍然很笨拙,但不是几分钟。不清楚你真正的问题是什么。你在寻找更好的解决方案吗?需要帮助改进当前版本吗?如果问题不清楚,请道歉。是的,我想要一个更好的解决方案,因为我的是1。太慢了。使用的正则表达式似乎不是Haskell惯用的(因为关于它们的信息很少)。我的解决方案主要是作为一个“这就是我到目前为止得到的”出发点给出的。我对激进的想法持开放态度。你怎么看这份文件?如果我使用main=Data.ByteString.interactive unescapeEntites
并使用time cat big.txt |/regex>/dev/null
我可以获得143M big.txt的30秒时间(这是Tagsoop中列出的所有实体,中间有很多“a”)。从这些间接的动作中仍然笨重,但不是几分钟。