VCARD格式需先合并折行再解析,因vCard强制BASE64编码且支持75字符折行(续行以空格或 开头);必须按BEGIN/END:VCARD界定联系人,处理ENCODING、CHARSET参数,并正确转义;, 等字符。

VCARD格式不是纯文本,直接用ifstream读会丢数据
很多开发者一上来就用 std::ifstream 逐行读取 VCF 文件,结果发现联系人字段错乱、中文乱码、换行丢失——因为标准 VCF(vCard 3.0/4.0)强制使用 BASE64 编码二进制内容(比如照片、logo),且支持长行自动折行(每行最多 75 字符,续行以
开头,注意空格)。直接按行切割会把一个属性值切碎。
正确做法是先做行合并,再解析键值对。核心步骤:读完整文件 → 合并被折行的行 → 按 : 或 ; 分割属性 → 处理 ENCODING=b, CHARSET=utf-8 等参数。
- 用
std::string一次性读入整个文件(避免getline截断折行) - 遍历每一行,若当前行以空格或
开头,就合并到上一行末尾 - 跳过注释行(以
#开头)和空行 - VCF 3.0 默认编码是
ISO-8859-1,但实际文件几乎都声明CHARSET=utf-8;没声明时按 UTF-8 解码更安全
解析BEGIN:VCARD / END:VCARD边界才能分出单个联系人
一个 VCF 文件常含多个联系人,靠 BEGIN:VCARD 和 END:VCARD 成对界定。不能只找第一个 FN: 或 TEL:——它们可能出现在注释或嵌套结构里(比如 vCard 4.0 支持 RELATED 嵌套 vCard)。
必须用状态机方式扫描:遇到 BEGIN:VCARD 进入收集状态,直到匹配到对应层级的 END:VCARD(注意嵌套时要计数,不过真实 VCF 几乎不嵌套)。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 忽略大小写比较
BEGIN:VCARD(规范允许大写/小写混合) - 记录当前是否在 vCard 块内,只在此状态下解析属性行
-
VERSION:3.0和VERSION:4.0属性决定后续解析规则(如 4.0 支持PARAMETER=VALUE写法,3.0 只支持PARAMETER;VALUE) - 不要依赖行序:
FN不一定在N前面,PHOTO可能在任意位置
解码BASE64照片时,vCard 3.0 和 4.0 的参数写法不同
读到 PHOTO;ENCODING=b;TYPE=JPEG: 或 PHOTO;encoding=b;type=jpeg;value=uri: 这类行,说明后面是 BASE64 数据。但参数语法差异会导致解码失败:
- vCard 3.0:参数用分号分隔,如
PHOTO;ENCODING=b;TYPE=PNG:,冒号后即 BASE64 字符串 - vCard 4.0:参数用分号+等号,且可能带
value=base64,如PHOTO;encoding=b;type=image/png;value=base64: - BASE64 数据可能跨多行(折行后仍需合并),且末尾可能有空格或换行符,解码前要
erase(remove_if(... isspace), end()) - 推荐用轻量级 BASE64 库(如
boost::beast::detail::base64或手写 64 字节查表解码),别用系统命令调用openssl base64
中文姓名/地址字段常含转义字符,不处理会显示为;或,
vCard 规范要求对逗号、分号、冒号、反斜杠本身进行转义,写成 ,、;、:、\。常见错误是把 N:张;三;San;Zhang;; 当作四个字段,其实这是标准的 N 属性(姓;名;中间名;前缀;后缀),其中 ; 是姓和名之间的分隔符,不是字段内容。
- 所有属性值中出现的
、N、、;、,、:、\都需还原(→换行,;→分号等) - 注意:vCard 3.0 中
表示换行,vCard 4.0 中改用或N,但实际文件混用严重 - 建议写一个通用 unescape 函数,遍历字符串,遇
x就替换,不要用正则——性能差且 C++11 std::regex 不支持部分转义 - 某些手机导出的 VCF 会把中文逗号(,)误写成英文逗号(,)再加转义,导致解析出错,需结合上下文判断

















