“字符串中的属性值”指HTML/XML等标签内key="value"格式的键值对,如id="header";C++需用regex_replace或状态机手动解析删除,不可依赖标准库内置函数。

什么是“字符串中的属性值”?先明确目标
你遇到的大概率不是标准 C++ 字符串操作题,而是处理类似 HTML、XML 或自定义配置格式的文本,比如 <div id="header" class="main" data-flag="true"> 中的 <code>id="header"、class="main" 这类 key="value" 形式的属性对。C++ 标准库没有“删除属性值”的内置函数,必须自己解析和替换。
用 std::regex_replace 快速剥离属性(C++11 及以上)
如果属性格式规整(如都是 空格+键名+="..."+(可选空格+>)),正则最直接。但要注意:标准库 regex 在 GCC 低版本(如 4.9)中 bug 较多,MSVC 和 Clang 表现更稳。
常见错误现象:std::regex_replace 不生效、崩溃、或删掉过多内容——多半是正则未转义或贪婪匹配越界。
- 匹配单个属性(含前后可能的空格):
R"(\s+\w+="[^"]*")" - 安全起见,用非贪婪或边界限定:
R"(\s+\w+="[^"]*?")"(需编译器支持非贪婪)或更稳妥的R"(\s+\w+="[^"]*")(?=\s|>|$)" - 替换为空字符串:
"",不是" ",否则残留多余空格 - 示例:
std::string s = "<div id='"header"' class='"main"'>";<br>std::regex attr_re(R"(\s+\w+="[^"]*")");<br>s = std::regex_replace(s, attr_re, ""); // → "<div>" <h3>不用正则时,手写状态机更可控</h3> <p>当输入不可信(如 value 中混有引号、转义、或无引号属性如 <code>checked</code>)、或需兼容旧编译器时,正则容易翻车。此时应按字符遍历,维护状态:<code>outside</code> / <code>in_tag</code> / <code>in_attr_name</code> / <code>in_attr_value</code>。</p> <p>关键点:</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> <ul> <li>只在 <code> 到 <code>></code> 之间才识别属性,避免误删文本中的 <code>key="val"</code></code> </li> <li>属性名后紧跟 <code>=</code> 才算属性;没等号的(如 <code>disabled</code>)是否删除,取决于你的需求</li> <li>引号类型要区分:<code>"</code> 和 <code>'</code> 都可能出现,且 value 内部可能有转义(如 <code>value="a&b"</code>),若需精确解析,建议用成熟 HTML 解析器(如 <code>libxml2</code>),而非纯字符串处理</li> <li>简单场景下,可跳过转义处理,仅按引号配对:记录当前是否在引号内,遇到匹配引号才退出 value 状态</li> </ul> <h3>注意 <code>std::string::erase</code> 的迭代器失效问题</h3> <p>如果选择边遍历边 <code>erase</code>,极易出错。例如:</p> <pre class="brush:php;toolbar:false;">for (auto it = s.begin(); it != s.end(); ++it) {<br> if (is_attr_start(it)) s.erase(it); // it 失效!后续 ++it 行为未定义正确做法是:
- 收集所有待删区间(起始/结束索引),逆序
erase,避免偏移干扰 - 或用
std::string::erase返回新迭代器:it = s.erase(it, end),然后不执行++it - 更推荐生成新字符串:遍历原串,只
push_back非属性部分字符,逻辑清晰不易错
真正麻烦的从来不是“删掉等号右边”,而是界定“哪里算属性开始、哪里算结束”。HTML 属性可以无引号、可换行、可含注释、可嵌套,纯字符串处理总有漏网之鱼。如果业务允许,优先交给专业解析器;如果只是简单模板清洗,正则 + 人工校验更省心。
- 收集所有待删区间(起始/结束索引),逆序










