如何用正则表达式检测C++硬编码字符串以实现国际化替换?
搞定C++各类字符串匹配的正则方案
先给你拆解C++里常见的字符串类型,再凑出能用的正则,顺便提几个避坑点:
1. 分类型写正则
先逐个搞定每种字符串的匹配规则:
- 普通窄字符串:就是咱们最常用的
"...",还要能识别转义字符(比如\"、\\)"([^"\\]|\\.)*" - 宽字符字符串:带
L前缀的L"..."L"([^"\\]|\\.)*" - 原始字符串(窄):
R"分隔符(内容)分隔符"这种,分隔符是可选的字母/数字/下划线R"([a-zA-Z0-9_]*)\(([\s\S]*?)\)\1" - 宽字符原始字符串:
LR"分隔符(内容)分隔符"或者RL"分隔符(内容)分隔符"(LR|RL)"([a-zA-Z0-9_]*)\(([\s\S]*?)\)\2"
2. 组合成完整正则
把上面的规则用|拼起来,一定要注意顺序——原始字符串的匹配要放在最前面,不然会被普通字符串的正则误抓开头的R":
(LR|RL)"([a-zA-Z0-9_]*)\(([\s\S]*?)\)\2"|R"([a-zA-Z0-9_]*)\(([\s\S]*?)\)\1"L"([^"\\]|\\.)*"|"([^"\\]|\\.)*"
提醒下:[\s\S]*?是用来匹配原始字符串里的任意内容(包括换行),非贪婪模式避免匹配到后面的闭合标记。
3. 别把注释里的字符串算进去
直接用正则会把//或者/* */里的字符串也抓出来,这肯定不是你要的,得先预处理文件:
- 先删掉所有单行注释:匹配
//.*$替换为空 - 再删掉多行注释:匹配
/\*[\s\S]*?\*/替换为空
处理完注释再跑正则,就不会误抓了。
4. 替换的具体逻辑
你得搞个全局计数器和一个索引表(比如用字典存):
- 计数器从1开始,索引表用来存「索引→原始字符串」
- 遍历每个CPP文件:
- 先做注释清理
- 用正则扫所有匹配的字符串
- 每抓到一个:
- 把原始字符串存到索引表,对应当前计数器值
- 把代码里的字符串替换成
s(计数器值) - 计数器加1
- 最后输出修改后的CPP文件和索引表(CSV或者JSON都行,方便后续翻译)
5. 几个必须注意的坑
- 字符串拼接:C++里
"hello" "world"会被编译器合并,正则会当成两个字符串抓,这时候你得加额外逻辑判断,把相邻的字符串合并成一个索引,不然会生成两个没必要的条目 - 宏定义里的字符串:比如
#define MSG "hello",这类字符串替换了会搞坏宏,得判断是不是在预处理指令里,直接跳过 - 字符字面量:别把
'a'当成字符串,上面的正则只会匹配双引号的,所以没问题,但要注意别写错正则把单引号也包含进去 - 后续做VS扩展:如果以后要搞VS插件,别死磕正则,用VS自带的Code Model API直接解析代码结构,能精准拿到字符串的位置和内容,比正则靠谱多了,正则毕竟是文本匹配,代码结构复杂了容易出错
内容的提问来源于stack exchange,提问作者Michael Chourdakis
相关产品推荐
相关产品推荐

