应使用状态机逐字符扫描,维护normal、in_double_quote、in_single_quote、in_block_comment、in_line_comment五种状态,并处理转义符,避免误删字符串内的注释符号。

如何用 C++ 删除字符串中的 C 风格注释(// 和 /* */)
直接删注释不难,但必须区分「字符串字面量内的 // 或 /*」和真实注释——否则会误删或破坏语法。核心是模拟编译器的词法扫描状态:跟踪是否在单引号、双引号、以及是否已进入块注释。
std::string 扫描时怎么避免误杀字符串里的注释符号
关键在于维护一个状态机,而不是靠 find 简单替换。常见错误是:str.replace() 多次修改导致下标错乱;或没处理转义引号(如 "a"//b" 中的 // 不是注释)。
- 状态包括:
normal(正常代码)、in_single_quote、in_double_quote、in_block_comment、in_line_comment - 遇到
'或"不切换引号状态(跳过转义) - 进入
/*后,直到匹配*/才退出in_block_comment;注意/*/不是结束,/**/才是 - 行注释
//只在normal状态下生效,且要忽略换行符前的所有内容
用 std::string::iterator 一次遍历完成删除的写法
推荐原地过滤(erase–remove 惯用法不适用,因为要判断上下文),用双指针更可控:
std::string remove_comments(const std::string& src) {
std::string out;
out.reserve(src.size());
enum { NORMAL, IN_SINGLE, IN_DOUBLE, IN_BLOCK, IN_LINE } state = NORMAL;
bool escaped = false;
<pre class='brush:php;toolbar:false;'>for (size_t i = 0; i < src.size(); ++i) {
char c = src[i];
if (escaped) {
out += c;
escaped = false;
continue;
}
if (c == '\') {
escaped = true;
out += c;
continue;
}
if (state == NORMAL) {
if (c == ''') state = IN_SINGLE;
else if (c == '"') state = IN_DOUBLE;
else if (i + 1 < src.size() && src[i] == '/' && src[i+1] == '*') {
state = IN_BLOCK; i++; continue;
}
else if (i + 1 < src.size() && src[i] == '/' && src[i+1] == '/') {
state = IN_LINE; i++; continue;
}
out += c;
}
else if (state == IN_SINGLE || state == IN_DOUBLE) {
if (c == (state == IN_SINGLE ? ''' : '"')) state = NORMAL;
out += c;
}
else if (state == IN_BLOCK) {
if (i + 1 < src.size() && src[i] == '*' && src[i+1] == '/') {
state = NORMAL; i++;
}
}
else if (state == IN_LINE) {
if (c == '
') {
state = NORMAL;
out += c;
}
}
}
return out;}
立即学习“C++免费学习笔记(深入)”;
为什么不能用正则(std::regex)简单匹配
std::regex 无法携带状态,无法区分字符串内和外部的 //。例如 R"("/*")" 或 "a//b" 会被错误匹配。即使写成 (? 也解决不了嵌套引号和转义问题。C++ 标准库 regex 在 C++11/14 中还有性能和 Unicode 兼容性缺陷,不建议用于此场景。
真正容易被忽略的是换行处理:行注释结束后必须保留换行符本身(否则多行变一行,破坏预处理逻辑),而块注释中的换行应完全丢弃——这点在手工解析里要显式判断。


















