I am parsing my vcard info (copied to a txt file)to extract name:number
and put it into a dictionary.
Data sample:
BEGIN:VCARD VERSION:2.1 N:MEO;Apoio;;; FN:Apoio MEO TEL;CELL;PREF:1696 TEL;CELL:162 00 END:VCARD BEGIN:VCARD VERSION:2.1 N:estrangeiro;Apoio MEO;no;; FN:Apoio MEO no estrangeiro TEL;CELL;PREF:+35196169000 END:VCARD
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)
With this I am getting a dictionary with names but for numbers I am getting None. {'name': None, 'name': None}
.
Can I do this with re? To extract both name and number with the same re.findall
expression?
My answer is based on zmos answer (you need to install vobject).
To get all vobjects from a vcf-file you can do something like this:
The documentation of
vobject
(on GitHub) is a little bit crappy so I looked into their code and figured out thatreadOne
is just calling a next onreadComponents
. So you can usereadComponents
to get a collection.You should better use an already existing library instead of trying to reinvent the wheel:
And then within python
and you're done!
so if you want to make a dictionary out of that, all you need to do is:
so you could make all that into a function:
From there, you can improve the code to handle multiple
vcard
s in a singlevobject
file, and update thedict
with more phones.N.B.: I leave you as an exercise to change the code above from reading one and only one vcard within a file, into a code that can read several vcards. Hint: read the documentation of
vobject
.N.B.: I'm using your data, and I'm considering that whatever you wrote, it is meaningless. But in doubt, I have modified the phone numbers.
just for the fun, let's have a look at your code. First there's an indentation issue, but I'll consider this is because of bad copy/paste ☺.
so first, there are two issues at line ②. You're opening a file using
open()
, but you're not closing the file. If you're calling this function to open one billion files, you'll starve your system's available file descriptors because you're not closing the files. As a good habit you should always use instead the with construct:that takes care of the fd for you, and better shows where you can make use of your opened file.
The second issue is that you're calling your variable
file
, which is shadowing thefile
type. Hopefully, thefile
type is very rarely used, but it's a bad habit to have, as you might one day not understand a bug that happens because you've shadowed a type with a variable. Just don't use it, it'll save you trouble one day.Line ⑤ and ⑥, you're applying a
re.findall
regex on each line. You should better usere.match()
, as you're already iterating over each line, and you won't haveFN: something
within that line. That will make you avoid the unnecessary''.join(name)
But instead of using a regex for such a simple thing, you'd better usestr.split()
:Line ⑦ is not only superfluous — if you use the
if
above, but actually wrong. Because then you'll skip all lines that does not haveFN:
within it, meaning that you'll never extract the phone numbers, just the name.Finally Line ⑧ makes absolutely no sense. Basically, what you're doing is equivalent of:
All in all, in your code, all you do is extract names, and you don't even bother with the telephones number. So when you say:
it makes no sense, as you're actually not trying to extract phone numbers.
yes, you could, with something that would look like (untested regex that's very likely to be not working), over the whole file, or at least for each vcard:
but why bother, when you've got a lib that does it perfectly for you!