用 C++ 编写解析器来解析给定的 HTML 实体

Posted

技术标签:

【中文标题】用 C++ 编写解析器来解析给定的 HTML 实体【英文标题】:Writing a parser in C++ to parse the given HTML entities 【发布时间】:2020-05-30 17:49:32 【问题描述】:

最近,我遇到了一个编码问题,我们必须解析提及的 HTML 实体。需要解析以下这些实体 -

"" ' 到 - ' >> < && ⁄

将给出一个字符串txt,必须按照上述规则进行解析。以下是我的方法,效果很好。

string parse(string txt)
    int n=txt.size();
    for(int i=0;i<n;i++)             //edit : why don't I get an error even though I loop for full length after erasing some elements of string?
            if(txt[i]=='&')
                if(i+5<n&&txt.substr(i,6)=="&quot;")
                    txt[i]='"';
                    txt.erase(i+1,5);
                
                else if(i+5<n&&txt.substr(i,6)=="&apos;")
                    txt[i]=(char)(39);            //I also wasn't able to do like this -txt[i]='\''; would be nice if someone tells why this gave error
                    txt.erase(i+1,5);
                
                else if(i+4<n&&txt.substr(i,5)=="&amp;")
                    txt[i]='&';
                    txt.erase(i+1,4);
                
                else if(i+3<n&&txt.substr(i,4)=="&gt;")
                    txt[i]='>';
                    txt.erase(i+1,3);
                
                else if(i+3<n&&txt.substr(i,4)=="&lt;")
                    txt[i]='<';
                    txt.erase(i+1,3);
                
                else if(i+6<n&&txt.substr(i,7)=="&frasl;")
                    txt[i]='/';
                    txt.erase(i+1,6);
                       
            
        
    return txt;

我觉得我以最粗鲁的方式做到了。但我想知道是否有另一种方法比我的代码更简单(可能更短)

感谢任何帮助或方法!

EDIT :正如评论引起我注意的那样,我的循环实际上使用了原始字符串长度n,但在循环减少txt 字符串长度时我正在删除一些元素。令人惊讶的是,我没有收到任何错误,如果有人解释原因会有所帮助吗?

【问题讨论】:

收集'&'和';'之间的所有字符首先,然后在一个固定的查找图中查找所有收集到的字符,替换它。据我估计,大约四分之一的代码。结束。 @SamVarshavchik 我尝试在我的代码中使用replace(),但这给了我分段错误......但是通过适当的实现可能会起作用。但我想知道是否有一种方法/内置方法可以替换我们传递给它的给定子字符串(在我们的例子中是 html 实体)的所有出现? 当我写“替换它”时,我并不一定是指实际使用replace()。 C++ 库中没有任何东西可以进行这种替换。此任务的全部目的是展示您自己实现新算法的能力,而不是依赖 C++ 库中现有的算法。 你确定上面的代码工作正常吗?你有n = txt.size(),但是你在擦除时调整n吗?似乎您的代码中的任何擦除都会导致越界访问。 @paler123 好消息!实际上这并没有给出任何错误。我不知道该功能是如何工作的,现在我真的想知道如何? 【参考方案1】:

以下是我建议解决此问题的方法:

0) 首先,我将创建一个具有正确格式输出的新字符串。这比必须就地修改字符串更容易 - 您只需一点一点地构建字符串。另外,我不知道就地修改它是否有益,每次你删除一些字符时,我都会想象元素会沿着元素被复制以保持内存在一起(连续)。

1) 使用 std::string::find 查找每个字符的下一次出现 2)您要查找的字符串中,选择下一个出现的字符串(最小的字符串::查找值) 3) 将直到该点的字符附加到输出字符串 4)附加替换文本而不是原始文本 5) 重复 - std::string::find 有一个可选的 pos 参数指示从哪里开始搜索 6) 当所有查找结果为 == std::string::npos 时循环结束

可能有很多方法可以解决这个问题,并且可能使用正则表达式的东西会更优雅,但我就是这样做的。

顺便说一句,与您的编辑有关,如果您在没有调试的情况下运行,则可能不会出现任何错误。我认为,如果您有访问冲突,控制台应用程序将退出而没有任何相关输出,您没有附加到调试器。这就是为什么如果可以的话,在调试环境中运行东西是个好主意。

编辑:使用 std::string::replace 是您可以在此处使用的另一个函数

【讨论】:

是的,您完全构建另一个字符串的方法肯定更有意义并且确实有效。虽然我想知道是否有更优雅的方式。就像在 python 中一样,我可以使用split()join() 轻松完成。您还提到了使用正则表达式。如果您知道,您可以将其添加到答案中吗? 编辑了我的答案以提及 std::string::replace - 这可能会使代码更简洁。也就是说,字符串操作在 C++ 中通常有点混乱——我经常求助于 boost 来查看是否已经有一个函数至少更接近我想要做的。恐怕我没有太多使用正则表达式,但我相信网络上会有一些很好的介绍性文章。 好的,我一定会上网看看。不管怎样,谢谢你的回答! 没问题!祝你在未来的编码工作中好运:)

以上是关于用 C++ 编写解析器来解析给定的 HTML 实体的主要内容,如果未能解决你的问题,请参考以下文章

用 C++ 解析/编写 CSV 的首选库是啥? [关闭]

如何在 Play 2.7 for Scala 中编写一个通用 JSON 解析器来验证入站请求?

如何用 C# 编写解析器? [关闭]

Java Debug 笔记:定制 Jackson 解析器来完成对复杂格式 XML 的解析

为啥要检查 (*argv == NULL)? [复制]

如何构建 html5lib 解析器来处理混合的 XML 和 HTML 标签?