【问题标题】:Extract HTML comments using C++ std::sregex_token_iterator使用 C++ std::sregex_token_iterator 提取 HTML 注释
【发布时间】:2018-08-06 22:30:02
【问题描述】:

我正在尝试从 HTML 源代码中提取 cmets 部分。它有点工作,但不完全。

<html><body>Login Successful!</body><!-- EXTRACT-THIS --></html>

到目前为止,这是我的代码:

#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <regex>

using namespace std;

int main()
{
    string s = 
    "<html><body>Login Successful!</body><!-- EXTRACT-THIS --></html>";

    // Regular expression to extract from HTML comment 
    // <!-- comment -->
    regex  r("[<!--\r\n\t][\r\n\t-->]");

    for (sregex_token_iterator it = sregex_token_iterator(
                                        s.begin(), 
                                        s.end(), 
                                        r, 
                                        -1); 
         it != sregex_token_iterator(); ++it)
    {
        cout << "TOKEN: " << (string) *it << endl;
    }

    return 0;
}

我想我的主要问题是有没有办法改进我的正则表达式?

【问题讨论】:

  • 如果 ECMAScript 支持原子组,您可以在 group 3 中找到 "(?&gt;(&lt;(?:(?:(?:(script|style|object|embed|applet|noframes|noscript|noembed)(?:\\s+(?&gt;\"[\\S\\s]*?\"|'[\\S\\s]*?'|(?:(?!/&gt;)[^&gt;])?)+)?\\s*&gt;)[\\S\\s]*?&lt;/\\2\\s*(?=&gt;))|(?:/?[\\w:]+\\s*/?)|(?:[\\w:]+\\s+(?:\"[\\S\\s]*?\"|'[\\S\\s]*?'|[^&gt;]?)+\\s*/?)|\\?[\\S\\s]*?\\?|(?:!(?:(?:DOCTYPE[\\S\\s]*?)|(?:\\[CDATA\\[[\\S\\s]*?\\]\\])|(?:ATTLIST[\\S\\s]*?)|(?:ENTITY[\\S\\s]*?)|(?:ELEMENT[\\S\\s]*?))))&gt;))*?(&lt;!--[\\S\\s]*?--&gt;)" 替换为 $1
  • 欢迎来到 Stack Overflow!如果您认为代码可以正常工作,请考虑在Code Review 上以更完整的方式展示您的工作(及其单元测试)。您可能会得到一些建议,使其更高效、更易于阅读和更好地测试。在您这样做之前,请务必先阅读A guide to Code Review for Stack Overflow users,因为那里有些事情的处理方式不同 - 例如。问题标题应该简单地说明代码做了什么,因为问题总是“我该如何改进?”。
  • 会做...但是我需要解决一些小问题。

标签: html c++ regex token


【解决方案1】:

让我们从包含多个评论部分的std::string 开始:

string s = "<html><body>Login Successful!</body><!-- EXTRACT-THIS --><p>Test</p><!-- XXX --></html>";

删除注释并打印 HTML 标签

如果你想从这个字符串中删除 HTML cmets,你可以这样做:

regex r("(<\\!--[^>]*-->)");

// split the string using the regular expression
sregex_token_iterator iterator = sregex_token_iterator(s.begin(), s.end(), r, -1);
sregex_token_iterator end;
for (; iterator != end; ++iterator)
{
    cout << "TOKEN: " << (string) *iterator << endl;
}

此代码打印:

TOKEN: <html><body>Login Successful!</body>
TOKEN: <p>Test</p>
TOKEN: </html>

删除 HTML 标签并打印注释

如果要从字符串中提取 cmets,可以像这样使用std::sregex_iterator

regex r("(<\\!--[^>]*-->)");

std::sregex_iterator next(s.begin(), s.end(), r);
std::sregex_iterator end;
while (next != end) {
    std::smatch match = *next;
    std::cout << match.str() << "\n";
    next++;
}

此代码打印:

<!-- EXTRACT-THIS -->
<!-- XXX -->

手动解析评论标签

另一种选择是手动查找并遍历开始和结束标签。我们可以使用std::string::find()std::string::substr() 方法:

const std::string OPEN_TAG = "<!--";
const std::string CLOSE_TAG = "-->";

auto posOpen = s.find(OPEN_TAG, 0);
while (posOpen != std::string::npos) {
    auto posClose = s.find(CLOSE_TAG, posOpen);
    std::cout << s.substr(posOpen, posClose - posOpen + CLOSE_TAG.length()) << '\n';
    posOpen = s.find(OPEN_TAG, posClose + CLOSE_TAG.length());
} 

【讨论】:

  • 我实际上想提取评论正文 EXTRACT_THIS 作为其中一个标记的一部分。
  • 那么您想要所有令牌(包括 cmets)还是只需要 cmets(跳过其他 HTML 标签)?
  • 我只想提取 cmets...有没有比标记化更有效的方法?
  • 感谢雨果的所有帮助。因此,您的解决方案适用于我当时给出的简单案例。我想简化它,所以我想这是我的错。如果我在 cmets 中有一个简单的词,例如:EXTRACT_THIS,则此方法有效。如果我有 XML 标签,它不会给出任何输出。您是否可以提供更新的正则表达式来提取 cmets 中的 XML: string s = "Login Success!";
  • @AnkurShah 我添加了一个新部分,解释如何在没有正则表达式的情况下执行此操作。第三种解决方案应该可以解决您的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-12
  • 1970-01-01
  • 2021-09-09
  • 2016-08-24
  • 1970-01-01
  • 2015-08-24
  • 1970-01-01
相关资源
最近更新 更多