c++oding="utf-8" ?>
最可靠的方法是用 std::string::find 与 erase 配合循环删除,每次 find 后记录位置 pos 并 erase(pos, tag.length()),再从 pos 继续查找以避免漏删或死循环。

用 std::string::find + std::string::erase 循环删除最可靠
直接调用 erase 删除所有匹配的起始标记(比如 "<tag></tag>")不能靠一次查找——因为 erase 会改变后续字符位置,下一次 find 必须从新起点继续找,否则会跳过紧邻的标记。
常见错误是写成 while (s.find(tag) != std::string::npos) s.erase(...) 却没更新查找位置,导致死循环或漏删。
- 每次
find后记录位置pos,成功则用erase(pos, tag.length())删除,再从pos继续找(不是pos + 1,因为可能有重叠或连续标记) - 若要删除的是“开始标记”而非完整标签(如只删 "
<div>" 但不碰 "</div>"),确保tag是精确字符串,不带通配或正则逻辑 - 注意:如果
tag为空,find总返回0,必须提前校验,否则无限循环
void remove_all_start_tags(std::string& s, const std::string& tag) {
if (tag.empty()) return;
size_t pos = 0;
while ((pos = s.find(tag, pos)) != std::string::npos) {
s.erase(pos, tag.length());
// 不加 pos++:防止 tag="<h3>用 <code>std::regex_replace</code> 简洁但有隐含开销</h3><p>适合一次性替换、脚本化处理或已有正则经验的场景;但 C++11 起的 <code>std::regex</code> 实现质量参差,MSVC 和 libstdc++ 在复杂模式下性能/兼容性差异明显,且构造 <code>std::regex</code> 对象本身有可观开销。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
- 若只是字面量删除(无特殊字符),必须对
tag做 regex 转义,否则 "<div>" 中的 <code>、<code>>会被当元字符解析 - 推荐用
std::regex_replace(s, std::regex(std::regex_replace(tag, std::regex(R"([.^$|\?*+()[{])"), R"($&)")), "")完成字面量转义(C++17 起支持R"(...)") - 反复调用时,应将
std::regex提取为静态局部变量,避免重复编译 - 读指针
r扫描全文,写指针w记录保留内容终点 - 每到一个疑似起点,先比对是否匹配
tag;匹配则跳过,不匹配则把当前字符拷贝到w - 注意边界:比对前检查
r + tag.length() ,防止越界访问 - 最后调用
s.resize(w)截断尾部冗余内容
手写双指针法在嵌入式或性能敏感场景更可控
当不能依赖 STL 正则、或字符串极大(MB 级)、或需严格控制内存分配时,双指针原地覆盖是最轻量方案。它不产生临时字符串,也不调用 find 的内部循环。
别忽略编码和标记嵌套带来的语义歧义
纯字符串删除无法区分“真实开始标记”和“被注释掉的标记”或“字符串字面量中的标记”。例如:<!-- <div> --> 或 const char* s = "<div>"; 中的 "<code><div>" 不该被删。<p>这意味着:如果需求本质是“HTML/XML 中移除起始标签”,那字符串级操作只是临时方案,长期应转向 HTML 解析器(如 pugixml、libxml2);否则删错内容的风险随文档复杂度指数上升。</p>
<p>真正难的不是怎么删,而是你怎么确定——此刻删的,确实是该删的那个“开始标记”。</p>
</div>










