探索通讯录VCard格式

2025-11-22 11:33:01

提示:本文是根据个人理解来简单探讨通讯录VCard格式以及介绍可以如何来解析VCard,这些内容并不依赖特定语言的使用。

文章目录

前言一、为什么需要通讯录VCard格式二、尝试解析VCard格式

1.读后缀名为vcf的信息2.VCard包含哪些元素3.将非结构数据转为结构数据三、部分VCard字段信息解读

1.Android VCard2.iCloud VCard总结

前言

最近业余在做一个Matlab通讯录App项目,感觉平时微信用多了,就很少关注到自己通讯录的日常维护,就正好利用这个项目来维护自己的通讯录。

随着时间的推移,自己接触到各行各业的人越来越多,这时候,在空闲之余梳理下自己的通讯录还是有必要的,不仅可以清楚哪些人对你是重要的,哪些人对你是不重要的,另外将这些人的公司、职称、微信号等常用信息填入自己通讯录,可以方便电话来电显示时迅速反应出来电者的身份。

开发过程中,我逐渐意识到,能否方便我导出的(表格)数据能够被手机直接读取,于是在网上看了一些资料,才逐步了解到有通讯录VCard这样一种格式。

本文并没有相关的代码示例,仅讨论我是如何理解VCard格式的,以及在开发时梳理的一些关于VCard格式的惯例(如Android和iCloud VCard字段认知),以上这些内容纯属从个人角度去探讨,并不是严谨的知识,但希望本文可以引发各位的小小思考。

一、为什么需要通讯录VCard格式

VCard(全称似乎是Versitcard,但无法肯定)格式是通讯录文件的导出格式,以.vcf作为后缀名,一般能用记事本直接打开,也能用Microsoft Outlook以个人名片的形式打开,但会出现乱码。VCard有其特定的格式规范,但其实没必要了解格式规范的所有细节,一种最直接的方式便是来做一次简单的“逆向工程”,将自己的安卓或苹果手机通讯录以VCard格式导出至本地电脑,进而反推出VCard格式的一些规范表达。

此时不妨可以思考:为什么需要有VCard格式?我们在开发通讯录App时,完全可以自己做个“数据规划师”,根据用户需求(用户通常是自己或是熟悉的人)合理设计(数据库)字段,那又何必需要另外花时间去学习VCard格式呢?

其实,通讯录VCard格式可理解为一类通用的协议或者类似于一种共享的模板。如果开发者A设计出的通讯录软件能够导出至开发者B设计出的通讯录软件,那么对开发者A而言,自然需要了解开发者B设计的通讯录软件的细节,可开发者A却不认识开发者B,那么该如何实现通讯录数据的共享,让开发者A和B的软件能够读取到合适的数据呢?

一种自然的方式是来设计出一个通用的模板,而这个模板又可以被所有的开发者认可并理解,于是开发者A就不必去理解开发者B设计的数据结构,只需要弄清楚两件事:(1)自己设计的数据能导出为通用模板;(2)模板数据能转换成自己设计的数据结构。最终,这个通用的模板能被所有开发者正确解读,成为了沟通的“桥梁”,而VCard格式正好承担了归属于通讯录文件的通用模板这一角色。

然而,VCard格式不是完美无暇的,因为VCard格式仅在形式上是抽象的,内容上暂时无法达成统一意见。这便引发了一个问题:从通讯录A导出的数据无法完全被通讯录B解读,即通讯录B只能解析出其中的部分数据,而部分信息会被忽略,这些信息有可能是关键的。其实,产生该问题的原因是通讯录A导出的通用模板在形式上能够被通讯录B理解,但某些内容无法被通讯录B考虑在内。

举个例子:共享单车是个好东西,如美团单车等。既然要想让单车被大众所接受,那么就得统一确定好单车的规格、型号、款式,比如黄色油漆、转铃、刹车装置、实心胎、坐垫等需要统一样式,这样才能便于大批量生产。可有些却无法统一,如坐垫的高度,有些人习惯于骑山地车,喜欢坐垫高些,这样骑行阻力小,而有些人觉得坐垫高的话人的重心太高,没有安全感,他们就喜欢低座垫。因此在坐垫高度方面是无法达成统一意见的,不过在解决此类意见矛盾时可将单车设计成可调节坐垫,于是让骑手自行选择合适的坐垫高度。举这个例子就是为了说明:虽然VCard格式在内容上没有完全统一,但也保留了一些惯例,内容不统一也不见得是件坏事。

本文第三部分将会简单梳理安卓VCard和苹果VCard的共同点和区别,另外在开发时建议在设计“导出VCard”功能时将其拆分为“导出安卓VCard”和“导出苹果VCard”,而导入VCard时可暂时不用区分导入的文件是安卓VCard还是苹果VCard。

二、尝试解析VCard格式

1.读取后缀名为VCF的文件

前文提到,VCard以vcf为后缀,可用记事本正常打开,那么VCard信息可以理解为等同于记事本里的文本信息,一般VCard以BEGIN:VCARD开头,并以END:VCARD结尾,用换行符分割。只要学过如何读写记事本里的文本信息,那么只需简单将目标文件后缀名txt改成vcf即可,其他部分不用做任何改动。

BEGIN:VCARD

...

END:VCARD

BEGIN:VCARD

...

END:VCARD

上面的这段块引用是用来描述两张通讯录名片(示例),具体内容暂以省略号代替。特别指出,省略号并不符合VCard规范,具体写入时需将其替换成恰当的规范性表达。

2.VCard包含哪些元素

下面以一个简单的案例来描述VCard包含哪些元素:

BEGIN:VCARD

VERSION:2.1

N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E8=AE=B8;=E5=AE=B6=E5=9B=A0;;;

TEL;HOME:095-14665945

END:VCARD

上面这段是描述一张完整的通讯录名片信息,具体包括Version,N和TEL共三行内容。每行内容可拆分成类别定义(如:TEL)、类别属性(如HOME)和类别值(如095-14665945)。其中,VERSION所在行没有类别属性。

看上去似乎不难,在解析时,首先将“BEGIN:VCARD...END:VCARD”拆分出每段字符串,然后再用正则表达式将需要的类别定义、属性和值抽取出来。但是,实际面临的情况是类别值可能会很长,在其他软件导出VCard格式时不能堆集在某一行,因此会出现换行的现象,此时如果将类别定义、属性和值合并为一组时,则会由于无法准确判别一组的结尾标识而造成解析不完全,否则直接拿换行符作为结尾标识即可。这样一想,直接用一次正则表达式解决好像有些困难,具体该如何处理则需要另外思考。

3.非结构数据转为结构数据

在上述的最后一段内容已交代,如果我来让VCard数据解析成自己预先设计好的数据结构,那么我并不会写一个单一函数直接完成解析步骤,而是需要将VCard数据中的类别定义、属性和值提取出来,这个过程便是将非结构化数据转为结构化数据的过程,然后,再将结构化数据根据一定的规则转换成自己设计的数据库。

这样做将带来一个好处:在自己开发一个类似的功能时可以复用这个过渡解析函数,因为这个解析函数在运行时将不会有任何的信息损失,保证信息的完整传递。接着再着手处理转换结构化数据的事,处理结构化数据可比处理非结构化数据容易得多呢。

在上述的例子中完整的类别定义、属性和值分别如下列示:

定义名称、属性和值

类别名称属性(或描述)值BEGINVCARDVERSION2.1NCHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE =E8=AE=B8;=E5=AE=B6=

E5=9B=A0;;;

TELHOME095-14665945ENDVCARD

三、部分VCard字段解读

这部分将具体介绍安卓和苹果VCard的字段含义,并以列表的形式呈现。

1. Android VCard

VERSION - 版本号(具体是什么的版本号未知)N - 姓名(姓和名是拆分的)FN - 姓名全称(full name)ORG - 公司(organization)TITLE - 职位NOTE - 备注,用来描述这个人的其他信息EMAIL - 邮箱TEL - 电话或手机号ADR - 地址(address)X-QQ - QQ号X-GROUP-MEMBERSHIP - 组名X-ANDROID-CUSTOM - 个性化设置,这里会介绍其中一类个性化设置的规范表达

类别名称属性描述介绍类别值的介绍备注N-拆分的姓和名 CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE

注:基本是这种固定的表达,编码方式是quoted-printable,这种编码方式很容易解码

;;;;

注:共四个分号,姓和名用符号;分割,至于姓名谁前谁后可以根据习惯来确定。是使用quoted-printable编码后的字符串。

quoted-printable该如何解析?

使用quoted-printable编码后的字符串是用“=”分割的16进制字符串,解析这段字符串首先将"="进行拆成N个16进制字符串,并转换成转换成10进制数字的数组(向量),然后将数组按照UTF-8方式转换成char类型,就是最终解码后的结果。而quoted-printable编码过程是反向过程,这里不再赘述。

FN-姓名全称CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE使用quoted-printable编码后的字符串如“=E8=AE=B8=E5=AE=B6=E5=9B=A0”解码后的结果为“许家因”ORG-公司名称同上同上TITLE-职位同上同上NOTE-备注同上同上EMAIL-邮箱HOME-表示家用邮箱同上TEL-电话 HOME-表示家用电话

CELL-表示手机号

1. 不使用quoted-printable加密

2. 如果有多个电话直接换行插入即可

ADR HOME;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE

HOME-常指家用地址

;;

;;;;

为编码后的地址名称,而为编码后的邮编,注意两者相对于分隔符“;”的位置。

使用quoted-printable编码后的字符串,并用符号“;”风格X-QQ QQ号 1. 不使用quoted-printable加密

2. 如果有多个QQ号直接换行插入即可

X-GROUP-MEMBERSHIP

组名

同上 X-ANDROID-CUSTOM

个性化设置

CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE vnd.android.cursor.item/nickname;;;;;;;;;;;;;;

设置昵称,为编码后的昵称,注意分隔符的数量

2. iCloud VCard

苹果手机导出通讯录需要依靠iCloud才能导出,下面梳理一些常用的字段含义:

N/FN/ORG/TITLE/EMAIL/TEL - 几乎和Android VCard完全相同item[i].ADR - 住址信息item[k].IMPP ... item[k].X-ABLabel - 由两行信息构成一个配对,属于个性化设置的范畴BDAY - 生日NICKNAME - 昵称item[k].X-ABDATE ... item[k].X-ABLabel:_$!!$_ - 由两行信息构成一个配对,属于个性化设置的范畴,这里表示纪念日

类别名称属性描述介绍类别值的介绍备注 N

FN

ORG

TITLE

EMAIL

TEL

[1]N/FN/ORG/TITLE: 一般无属性描述

[2]TEL:type=HOME;type=VOICE表示家庭电话;type=CELL;type=VOICE表示手机号;

[3]type=INTERNET;type=WORK表示工作邮箱

[1]N: ;;;; 共四个分号,姓和名用符号;分割,至于姓名谁前谁后可以根据习惯来确定;

[2]FN/ORG/TITLE的值为普通字符串

[3]EMAIL: 邮箱字符串

[4]TEL: 家庭电话格式

a. 033-77777777

b. 05166666666

c. 12345678

手机格式

a. 18888888888

b. 188-3122-5577

c. 188 3122 5575

d. +86 18218218218

e. 86 15015015015

item[i].ADR type=HOME;type=pref 家庭住址

如果有多个地址,则type=pref可以省略,换言之type=pref是在item[i].ADR第一次出现时才添加的

;;

;;;;

为地址名称,而为邮编,注意两者相对于分隔符“;”的位置。

item[k].IMPP ... item[k].X-ABLabel 场景1-微信:

[1]item[k].IMPP X-SERVICE-TYPE=微信;x-teamidentifier=88L2Q4487U;x-bundleidentifiers=com.tencent.xin;x-apple

[2]item[k].X-ABLabel 无属性描述

场景1-QQ:

[1]item[k].IMPP X-SERVICE-TYPE=QQ:x-apple

[2]item[k].X-ABLabel 无属性描述

场景1-微信:X-ABLabel:微信

场景1-QQ:X-ABLabel:QQ

item[k].IMPP第一次出现时需添加“type=pref”BDAYvalue=dateyyyy-mm-dd 如:2024-01-09如果年份未知,则iphone会设置一个充分早的固定年份NICKNAME昵称字符串item[k].X-ABDATE ... item[k].X-ABLabel:_$!!$_ 1. yyyy-mm-dd 如:2024-01-09

2. item[k].X-ABLabel:_$!!$_是纪念日的固定搭配

简单概括,iCloud VCard和Android VCard在很多方面是类似的,如昵称、公司、手机、邮箱等,Android VCard在获取类别值时需要多考虑一个quoted-printable编码问题。尽管iCloud VCard和Android VCard显然都符合VCard形式上的要求,但在个性化设置方面,他们是有较大区别的。

第三部分暂时不去介绍关于Android头像(PHOTO)的VCard格式。此外,iCloud头像的VCard格式尚未可知。后期会交流关于Android头像(PHOTO)的VCard格式以及如何用Matlab解析。

总结

本文是根据个人理解来简单探讨通讯录VCard格式以及介绍可以如何来解析VCard。首先是分析VCard格式的必要性,其次是尝试如何解析VCard格式,最后是罗列Android VCard格式和iCloud VCard格式在一些具体内容上的表达。

一些介绍VCard格式的其他网络资源:

VCard格式规范 [MS-OXVCARD]: vCard to Contact Object Conversion Algorithm