I thought of this project in order to convert some of my phone’s contact numbers from their national format (the one with the 00 in front of the number) to the one that the local providers recognize.
It was a bit challenging as it had to do with things like seeking from information inside data frames, converting data frames, applying changes, save data frames the way user wants etc. Some new aspects also stood on the way. Some of them I cannot figure, until this point, how to solve them.
The program is very different in its final form than it was thought first to be. It consists of many different small sub programs and it gives you four choices. Firstly, it can change a number and name of a contact that the user is going to point. Secondly, it allows you to add a new number to the existing phone contacts file. Thirdly, the user can find a contact’s number just by typing some letters of the contact’s name and then choose the contact that he wants from a list of contacts that will match the letters that provided, and finally it allows you to create a new phone contacts file.
SQL[2]
It makes use of the sqldf library[3]. I believe that the SQL querying[4] is much easier than do the same thing and write it in basic R code (sometimes), that’s why I preferred to make use of this library.
Problems
Of course there are some problems that exist and until now, I cannot solve them because they are out of my knowledge and I guess that they are hard even for the majority of the advanced programmers, except if someone has worked before on this kind of stuff.
The main and big problem that remains is that if the user has contacts that contain characters other than the basic Latin alphabet. At the end the program uses the command write.table() to export the .vcf file. When the user tries to read this file from his phone (in this project on android operation system based phone) an error message appears telling that some characters are in front of the card coding others than it should be.
In my case, it was the UTF-8[5] Byte Order Marks[6] characters. As far as I know, the windows system use some marks in files like .txt, which have no metadata files, in order to indicate what kind of encoding is being used. These are the Byte Order Marks. And as my contacts had UTF-8 characters there were these marks.
In first sight, they cannot be seen by the user. But, there are many ways one can see if these characters exist in the file and I found one way, indicated by a StackOverflow.com[7] user, even to delete them from the exported file, so the file can be readable again from the phone device.
The first way to see the Byte Order Marks in the text is the use of regexpr() command in the R Language. The user asks to see in what position is the first letter of the imported .vcf file (which ise the letter B from the BEGIN:VCARD). It gives the number 4, meaning that it is in the fourth position, even if it cannot be seen. So, that tells that there is something in the other three positions before B. The other way is to analyze the exported file with a hexadecimal [8] analyzer. That gives a clear view of the file. I used the XVI32[9] to analyze and delete the Byte Order Marks from my exported file.
The program still has problems with contacts that contain other data than the basics (name and phone number). For example, it might not work well if there is a photo attached to the contact or if there is more than one phone numbers. It uses just the basics:
BEGIN:VCARD
VERSION:3.0
N:;NAME;;;
FN:NAME
TEL;TYPE=CELL:PHONE NUMBER
END:VCARD
Example pictures:
Pic1:
Pic2:
References:
- vCard format: http://en.wikipedia.org/wiki/VCard
- SQL querying language: http://el.wikipedia.org/wiki/SQL
- SQLdf library for R Language: https://code.google.com/p/sqldf/
- SQL basic querying: http://www.w3schools.com/sql/
- The UTF-8 format: http://en.wikipedia.org/wiki/UTF-8
- Byte Ordering Marks: http://en.wikipedia.org/wiki/Byte_order_mark
- Stack Overflow: http://stackoverflow.com/questions/20161273/vcf-file-import-error
- Hexadecimal Numbers: http://en.wikipedia.org/wiki/Hexadecimal
- The XVI32 Hexadecimal Analyzer freeware profram: http://www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm
The code of the program:
[code language=”r”]
contacts<-function() {
library("sqldf")
print("Please specify what you want to do")
print("Type 1 To change the number and/or name")
print("Type 2 To add a new number")
print("Type 3 To find a number")
print("Type 4 To create a new contact file (.vcf)")
whatchange<-readline("Please type the number of the action: ")
conditions<-c("1","2","3","4")
if(whatchange=="1") {
print("Please provide the contacts file (.vcf)")
file<-file.choose()
cons<-read.csv(file,header=F,sep=",",colClasses="character")
con<-readLines(file)
n<-regexpr("FN(.*?)$",con)
w<-regmatches(con,n)
names<-gsub("FN:","",w)
nameframe<-data.frame(names)
name<-readline("Type the name (or part of it) of the contact you want to change:")
contact1<-fn$sqldf("select * from nameframe where names like ‘%$name%’")
if(nrow(contact1)>1){print(contact1)
contactchoose<-readline("Please choose the number of the contact as displayed above:")
}else{contactchoose=1}
print(paste("Your contact name you want to change is:",contact1[contactchoose,]))
xx<-as.character(contact1[contactchoose,])
xxx<-paste("FN:",xx,sep="")
nameline<-which(con==xxx)
contnumber<-gsub("\\D","",con[nameline+1])
print(paste("and the phone number of the contact is:",contnumber))
Continueeee<-readline("Press ENTER to continue, otherwise ESC to terminate the program")
namenew1<-readline("Please type the new name of this contact(press ENTER to leave it the same):")
if(namenew1==""){
cons2<- as.data.frame(sapply(cons,gsub,pattern=contact1[contactchoose,],replacement=contact1[contactchoose,]))
}
else{
cons2<- as.data.frame(sapply(cons,gsub,pattern=as.character(contact1[contactchoose,]),replacement=namenew1))
}
numnew1<-readline("Please type the new number of this contact (press ENTER to leave it the same):")
if(numnew1==""){
cons3<- as.data.frame(sapply(cons2,gsub,pattern=contnumber,replacement=contnumber))
##must change the name of frame to cons3 because if I put cons2 and sapply to cons then again it
##changes the cons frame from the begining and the changed name has been lost!!!!Must watch it out!!!
}
else{
cons3<- as.data.frame(sapply(cons2,gsub,pattern=contnumber,replacement=numnew1))
}
filename<-readline("Please type a name for the file to save it:")
write.table(cons3,file=paste(filename,".vcf",sep=""),row.names=F,col.names=F,quote=FALSE)
}
if(whatchange=="2") {
print("Please provide the contacts file (.vcf)")
file<-file.choose()
cons<-read.csv(file,header=F,sep=",",colClasses="character")
con<-readLines(file)
n<-regexpr("FN(.*?)$",con)
w<-regmatches(con,n)
names<-gsub("FN:","",w)
nameframe<-data.frame(names)
newnameadd<-readline("Please give the name of the new contact:")
newnumbadd<-readline("Please give the number of the new contact:")
newcontact<-data.frame(c("BEGIN:VCARD","VERSION:3.0",paste("N:;",newnameadd,";;;",sep=""),
paste("FN:",newnameadd,sep=""),
paste("TEL;TYPE=CELL:",newnumbadd,sep=""),"END:VCARD"))
names(newcontact)[1]<-paste("V1")
##change the name of the column in order to rbind them with the main contacts frame
cons2<-rbind(cons,newcontact)
filename<-readline("Please type a name for the file to save it:")
write.table(cons2,file=paste(filename,".vcf",sep=""),row.names=F,col.names=F,quote=FALSE)
}
if(whatchange=="3") {
print("Please provide the contacts file (.vcf)")
file<-file.choose()
cons<-read.csv(file,header=F,sep=",",colClasses="character")
con<-readLines(file)
n<-regexpr("FN(.*?)$",con)
w<-regmatches(con,n)
names<-gsub("FN:","",w)
nameframe<-data.frame(names)
name<-readline("Give part of the name of contact you want to find:")
contact1<-fn$sqldf("select * from nameframe where names like ‘%$name%’")
if(nrow(contact1)>1){print(contact1)
contactchoose<-readline("Please choose the number of the contact as displayed bellow:")
}else{contactchoose=1}
print(paste("Your contact you are looking for is:",contact1[contactchoose,]))
xx<-as.character(contact1[contactchoose,])
xxx<-paste("FN:",xx,sep="")
concons<-fn$sqldf("select * from cons where V1 like ‘%$xxx%’")
nameline<-which(con==xxx)
contnumber<-gsub("\\D","",con[nameline+1])
print(paste("and the number is:",contnumber))
}
if(whatchange=="4"){
newfilename<-readline("Please type the name of the new phone contact file:")
newfilecontact<-readline("Please type the first and last name of the contact:")
newfilenumber<-readline("Please type the number of the contact:")
newcontact<-data.frame(c("BEGIN:VCARD","VERSION:3.0",paste("N:;",newfilecontact,";;;",sep=""),
paste("FN:",newfilecontact,sep=""),
paste("TEL;TYPE=CELL:",newfilenumber,sep=""),"END:VCARD"))
names(newcontact)[1]<-paste("V1")
##change the name of the column in order to rbind them with the main contacts frame
write.table(newcontact,file=paste(newfilename,".vcf",sep=""),row.names=F,col.names=F,quote=FALSE)
print("Your new phone contact file has been created!!!")
}
if(!whatchange%in%conditions)stop("Please specify one of the given actions")
}
[/code]
Leave a Reply