你最好使用已经
existing library
而不是试图重塑车轮:
pip install vobject
然后在python中
>>> import vobject
>>> s = """\
... BEGIN:VCARD
... VERSION:2.1
... N:MEO;Apoio;;;
... FN:Apoio MEO
... TEL;CELL;PREF:0123456789
... TEL;CELL:0123456768
... END:VCARD
... BEGIN:VCARD
... VERSION:2.1
... N:estrangeiro;Apoio MEO;no;;
... FN:Apoio MEO no estrangeiro
... TEL;CELL;PREF:+0123456789
... END:VCARD """
>>> vcard = vobject.readOne(s)
>>> vcard.prettyPrint()
VCARD
VERSION: 2.1
TEL: 1696
TEL: 162 00
FN: Apoio MEO
N: Apoio MEO
你就完了!
所以,如果你想用它编一本词典,你需要做的就是:
>>> {vcard.contents['fn'][0].value: [tel.value for tel in vcard.contents['tel']] }
{'Apoio MEO': ['1696', '162 00']}
所以你可以把所有这些都变成一个函数:
def parse_vcard(path):
with open(path, 'r') as f:
vcard = vobject.readOne(f.read())
return {vcard.contents['fn'][0].value: [tel.value for tel in vcard.contents['tel']] }
从那里,您可以改进代码以处理多个
vcard
s在单个
vobject
文件,并更新
dict
更多的手机。
N、 我留给你一个练习,把上面的代码从一个文件中只能读取一张vcard改为可以读取多张vcard的代码。提示:
read the documentation of
vobject
.
N、 我在使用你的数据,我认为无论你写什么,都没有意义。但毫无疑问,我修改了电话号码。
为了好玩,让我们看看你的代码。首先是缩进问题,但我认为这是因为复制/粘贴不好。
â import re
â¡ file = open('Contacts.txt', 'r')
⢠contacts = dict()
⣠for line in file:
⤠name = re.findall('FN:(.*)', line)
⥠nm = ''.join(name)
⦠if len(nm) == 0:
â§ continue
⨠contacts[nm] = contacts.get(nm)
â© print(contacts)
首先,第行有两个问题。您使用
open()
,但你不会关闭文件。如果你调用这个函数来打开10亿个文件,你会因为没有关闭这些文件而耗尽系统的可用文件描述符。作为一个好习惯,您应该始终使用with结构:
with open('...', '...') as f:
⦠your code here â¦
这将为您处理fd,并更好地显示您可以在哪里使用打开的文件。
第二个问题是您调用了变量
file
,这是对
文件
类型希望
文件
类型很少被使用,但这是一个坏习惯,因为有一天你可能不理解会发生的错误,因为你用变量隐藏了一个类型。别用它,总有一天会给你省事的。
行?和,您正在应用
re.findall
每行的正则表达式。你最好使用
re.match()
,因为您已经在每一行上迭代
FN: something
在这条线内。这将使你避免不必要的
''.join(name)
但是,与其使用正则表达式来处理这么简单的事情,不如使用
str.split()
:
if 'FN:' in line:
name = line.split(':')[-1]
如果使用
if
以上,但实际上是错误的。因为这样你就会跳过所有没有
FN:
这意味着你永远不会提取电话号码,只提取姓名。
最后,第§行完全没有意义。基本上,你所做的相当于:
if nm in contacts.keys():
contacts[nm] = contacts[nm]
else:
contacts[nm] = None
总之,在你的代码中,你所做的就是提取姓名,你甚至不需要去管电话号码。所以当你说:
有了这个,我得到了一本有名字但有数字的字典
这毫无意义,因为你实际上并没有试图提取电话号码。
我可以用re做这个吗?提取相同的名称和编号
re.findall公司
表示
是的,您可以使用类似于(未经测试的正则表达式很可能无法工作)的方法,遍历整个文件,或者至少遍历每个vcard:
FN:(?P<name>[^\n]*).*TEL[^:]*:(?P<phone>[^\n])
但是,当你有一个为你做得很完美的lib时,何必费心呢!