问题
I have a VCard String that I want to parse and insert to the phone's contacts store. I checked this link http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207024(v=vs.105).aspx#BKMK_UsingtheRemoteIdHelperclass
and found the following method
ContactInformation info = await ContactInformation.ParseVcardAsync(IInputStream vcard);
how can I convert my VCard String to an IInputStream so that I can parse it ?
Thanks
回答1:
I Used this class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
namespace aaa
{
/// <summary>
/// Container class for vCard properties of vCard 2.1.
/// Considering current implementation of vCard support in MS Outlook, MS Outlook Express, Yahoo Mail and Eudora etc.,
/// the following properties and attributes are not supported:
/// * Photo
/// * Address labels
/// * Delivery address types
/// * Mailer
/// * Timezone
/// * EMail types
/// * Sound
/// * Public key
/// * Extensions
/// * Geo
///
/// So this vCard implementation is expected to be compatible with standard vCard fields of the vCard generated by these programs.
/// </summary>
public class VCard
{
readonly char[] lineBreak = { '\n', '\r' };
#region Singlar Properties
private string formattedName;
public string FormattedName
{
get { return formattedName; }
set { formattedName = value.TrimEnd(lineBreak); }
}
string surname;
public string Surname
{
get { return surname; }
set { surname = value.TrimEnd(lineBreak); }
}
private string givenName;
public string GivenName
{
get { return givenName; }
set { givenName = value.TrimEnd(lineBreak); }
}
private string middleName;
public string MiddleName
{
get { return middleName; }
set { middleName = value.TrimEnd(lineBreak); }
}
private string prefix;
public string Prefix
{
get { return prefix; }
set { prefix = value.TrimEnd(lineBreak); }
}
private string suffix;
public string Suffix
{
get { return suffix; }
set { suffix = value.TrimEnd(lineBreak); }
}
private string title;
public string Title
{
get { return title; }
set { title = value.TrimEnd(lineBreak); }
}
private DateTime bday;
public DateTime Birthday
{
get { return bday; }
set { bday = value; }
}
private DateTime rev = DateTime.MinValue;
/// <summary>
/// If Rev in vCard is UTC, Rev will convert utc to local datetime.
/// </summary>
public DateTime Rev
{
get { return rev; }
set { rev = value; }
}
private string org;
public string Org
{
get { return org; }
set { org = value.TrimEnd(lineBreak); }
}
private string department;
public string Department
{
get { return department; }
set { department = value.TrimEnd(lineBreak); }
}
private string note;
public string Note
{
get { return note; }
set { note = value.TrimEnd(lineBreak); }
}
private string role;
public string Role
{
get { return role; }
set { role = value.TrimEnd(lineBreak); }
}
#endregion
#region Property Collections with attribute
private Collection<Address> addresses = new Collection<Address>();
public Collection<Address> Addresses
{
get { return addresses; }
set { addresses = value; }
}
private Collection<PhoneNumber> phones = new Collection<PhoneNumber>();
public Collection<PhoneNumber> Phones
{
get { return phones; }
set { phones = value; }
}
private Collection<EmailAddress> emails = new Collection<EmailAddress>();
public Collection<EmailAddress> Emails
{
get { return emails; }
set { emails = value; }
}
private Collection<URL> urls = new Collection<URL>();
public Collection<URL> URLs
{
get { return urls; }
set { urls = value; }
}
#endregion
}
/// <summary>
/// Read text and create data fields of collections.
///
/// When testing, please be aware the following facts:
/// vCard standard has been around for more than 10 years, and widely accpeted by the industries. However,
/// the implementations from different vendors are a bit buggy, resulting data corruption during data exchanges.
/// For example
/// 1. MS Outlook 2003 can handle Unicode. When exporting to vCard, non-ASCII characters are encoded into QuotedPrintable over UTF8,
/// however, when importing, Outlook will fail to import those characters.
/// 2. Yahoo has similar problem. In additon, Rev in Yahoo vCard is not DateTime, a bit doggy.
///
/// These applications just can not eat their own dog food. So when you are testing the exchanges of vCard, keep these facts in mind.
/// </summary>
public class VCardReader
{
const string regxLine = @"((?<strElement>[^\;^:]*) ((;(ENCODING=)?(?<strAttr>(QUOTED-PRINTABLE)))|(;CHARSET=UTF-?8)|(;[\w]*))* (:(?<strValue> (([^\n\r]*=[\n\r]+)*[^\n\r]*[^=][\n\r]*) )))";
const string regxN = @"(?<strElement>(N)) ((;(ENCODING=)?(?<strAttr>(QUOTED-PRINTABLE)))|(;CHARSET=UTF-?8))* (:(?<strSurname>(([^;^\n\r]*(=\n\r)?)*[^;^\n\r]*[^;]*(\n\r)?) ))(;(?<strGivenName>(([^;^\n\r]*(=\n\r)?)*[^;^\n\r]*[^;]*(\n\r)?) ))? (;(?<strMidName>(([^;^\n\r]*(=\n\r)?)*[^;^\n\r]*[^;]*(\n\r)?) ))? (;(?<strPrefix>(([^;^\n\r]*(=\n\r)?)*[^;^\n\r]*[^;]*(\n\r)?) ))? (;(?<strSuffix>(([^;^\n\r]*(=\n\r)?)*[^;^\n\r]*[^;]*(\n\r)?) ))?";
const string regxFN = @"(?<strElement>(FN))((;(ENCODING=)?(?<strAttr>(QUOTED-PRINTABLE)))|(;CHARSET=UTF-?8))* (:(?<strFN>(([^\n\r]*=[\n\r]+)*[^\n\r]*[^=][\n\r]*) ))";
const string regxTitle = @"(?<strElement>(TITLE))((;(ENCODING=)?(?<strAttr>(QUOTED-PRINTABLE)))|(;CHARSET=UTF-?8))* (:(?<strTITLE>[^\n\r]*))";
const string regxOrg = @"(?<strElement>(ORG)) ((;(ENCODING=)?(?<strAttr>(QUOTED-PRINTABLE)))|(;CHARSET=UTF-?8))* (:(?<strORG>(([^;^\n\r]*(=\n\r)?)*[^;^\n\r]*[^;]*(\n\r)?) ))(;(?<strDept>(([^;^\n\r]*(=\n\r)?)*[^;^\n\r]*[^;]*(\n\r)?) ))?";
const string regxAdr = @"(?<strElement>(ADR)) (;(?<strAttr>(HOME|WORK)))?((;(ENCODING=)?(?<strAttr>(QUOTED-PRINTABLE)))|(;CHARSET=UTF-?8))*(:(?<strPo>([^;]*))) (;(?<strBlock>([^;]*))) (;(?<strStreet>([^;]*))) (;(?<strCity>([^;]*))) (;(?<strRegion>([^;]*))) (;(?<strPostcode>([^;]*)))(;(?<strNation>(([^;^\n\r]*(=\n\r)?)*[^;^\n\r]*[^;]*(\n\r)?) ))";
const string regxNote = @"((?<strElement>(NOTE)) ((;CHARSET=UTF-?8)|(;(ENCODING=)?(?<strAttr>(QUOTED-PRINTABLE))))* (:(?<strValue> (([^\n\r]*=[\n\r]+)*[^\n\r]*[^=][\n\r]*) )))";
const string regxRole = @"(?<strElement>(ROLE)) ((;(ENCODING=)?(?<strAttr>(QUOTED-PRINTABLE)))|(;CHARSET=UTF-?8))* (:(?<strROLE>(([^\n\r]*=[\n\r]+)*[^\n\r]*[^=][\n\r]*) ))";
/// <summary>
/// Analyze vCard text into vCard properties.
/// </summary>
/// <param name="vCardText">vCard text.</param>
/// <returns>vCard object.</returns>
public static VCard ParseText(string vCardText)
{
VCard v = new VCard();
RegexOptions options = RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace;
Regex regex;
Match m;
MatchCollection mc;
// NameValueCollection vCardLines = new NameValueCollection();
regex = new Regex(regxLine, options);
MatchCollection matches = regex.Matches(vCardText);
foreach (Match match in matches)
{
string ss;
string vCardLine = match.Value;
switch (match.Groups["strElement"].Value)
{
case "FN":
regex = new Regex(regxFN, options);
m = regex.Match(vCardLine);
if (m.Success)
{
if (m.Groups["strAttr"].Value == "QUOTED-PRINTABLE")
v.FormattedName = QuotedPrintable.Decode(m.Groups["strFN"].Value);
else
v.FormattedName = m.Groups["strFN"].Value;
}
break;
case "N":
regex = new Regex(regxN, options);
m = regex.Match(vCardLine);
if (m.Success)
{
if (m.Groups["strAttr"].Value == "QUOTED-PRINTABLE")
{
v.Surname = QuotedPrintable.Decode(m.Groups["strSurname"].Value);
v.GivenName = QuotedPrintable.Decode(m.Groups["strGivenName"].Value);
v.MiddleName = QuotedPrintable.Decode(m.Groups["strMidName"].Value);
v.Prefix = QuotedPrintable.Decode(m.Groups["strPrefix"].Value);
v.Suffix = QuotedPrintable.Decode(m.Groups["strSuffix"].Value);
}
else
{
v.Surname = m.Groups["strSurname"].Value;
v.GivenName = m.Groups["strGivenName"].Value;
v.MiddleName = m.Groups["strMidName"].Value;
v.Prefix = m.Groups["strPrefix"].Value;
v.Suffix = m.Groups["strSuffix"].Value;
}
}
break;
case "TITLE":
regex = new Regex(regxTitle, options);
m = regex.Match(vCardLine);
if (m.Success)
{
if (m.Groups["strAttr"].Value == "QUOTED-PRINTABLE")
v.Title = QuotedPrintable.Decode(m.Groups["strTITLE"].Value);
else
v.Title = m.Groups["strTITLE"].Value;
}
break;
case "ORG":
regex = new Regex(regxOrg, options);
m = regex.Match(vCardLine);
if (m.Success)
{
if (m.Groups["strAttr"].Value == "QUOTED-PRINTABLE")
{
v.Org = QuotedPrintable.Decode(m.Groups["strORG"].Value);
v.Department = QuotedPrintable.Decode(m.Groups["strDept"].Value);
}
else
{
v.Org = m.Groups["strORG"].Value;
v.Department = m.Groups["strDept"].Value;
}
}
break;
case "BDAY":
regex = new Regex(@"(?<strElement>(BDAY)) (:(?<strBDAY>[^\n\r]*))", options);
m = regex.Match(vCardLine);
if (m.Success)
{
string bdayStr = m.Groups["strBDAY"].Value;
if (!String.IsNullOrEmpty(bdayStr))
{
string[] expectedFormats = { "yyyyMMdd", "yyMMdd", "yyyy-MM-dd" };
v.Birthday = DateTime.ParseExact(bdayStr, expectedFormats, null, System.Globalization.DateTimeStyles.AllowWhiteSpaces);
}
}
break;
case "REV":
regex = new Regex(@"(?<strElement>(REV)) (;CHARSET=utf-8)? (:(?<strREV>[^\n\r]*))", options);
m = regex.Match(vCardLine);
if (m.Success)
{
string revStr = m.Groups["strREV"].Value;
if (!String.IsNullOrEmpty(revStr))
{
string[] expectedFormats = { "yyyyMMddHHmmss", "yyyyMMddTHHmmssZ" };
v.Rev = DateTime.ParseExact(revStr, expectedFormats, null, System.Globalization.DateTimeStyles.AllowWhiteSpaces);
}
}
break;
case "EMAIL":
regex = new Regex(@"((?<strElement>(EMAIL)) ((;(?<strPref>(PREF))))* (;[^:]*)* (:(?<strValue>[^\n\r]*)))", options);
mc = regex.Matches(vCardLine);
if (mc.Count > 0)
{
for (int i = 0; i < mc.Count; i++)
{
EmailAddress email = new EmailAddress();
v.Emails.Add(email);
m = mc[i];
email.Address = m.Groups["strValue"].Value;
if (m.Groups["strPref"].Value == "PREF")
email.Pref = true;
}
}
break;
case "TEL":
regex = new Regex(@"((?<strElement>(TEL)) ((;(?<strType>(VOICE|CELL|PAGER|MSG|FAX)))| (;(?<strAttr>(HOME|WORK)))| (;(?<strPref>(PREF)))?)* (:(?<strValue>[^\n\r]*)))", options);
mc = regex.Matches(vCardLine);
if (mc.Count > 0)
{
for (int i = 0; i < mc.Count; i++)
{
PhoneNumber phone = new PhoneNumber();
v.Phones.Add(phone);
m = mc[i];
phone.Number = m.Groups["strValue"].Value;
ss = m.Groups["strAttr"].Value;
if (ss == "HOME")
phone.HomeWorkTypes = HomeWorkTypes.HOME;
else if (ss == "WORK")
phone.HomeWorkTypes = HomeWorkTypes.WORK;
if (m.Groups["strPref"].Value == "PREF")
phone.Pref = true;
CaptureCollection types = m.Groups["strType"].Captures;
foreach (Capture capture in types)
{
switch (capture.Value)
{
case "VOICE":
phone.PhoneTypes |= PhoneTypes.VOICE;
break;
case "CELL": phone.PhoneTypes |= PhoneTypes.CELL;
break;
case "PAGER": phone.PhoneTypes |= PhoneTypes.PAGER;
break;
case "MSG": phone.PhoneTypes |= PhoneTypes.MSG;
break;
case "FAX": phone.PhoneTypes |= PhoneTypes.FAX;
break;
}
}
}
}
break;
case "ADR":
regex = new Regex(regxAdr, options);
mc = regex.Matches(vCardLine);
if (mc.Count > 0)
{
for (int i = 0; i < mc.Count; i++)
{
Address address = new Address();
v.Addresses.Add(address);
m = mc[i];
ss = m.Groups["strAttr"].Value;
if (ss == "HOME")
address.HomeWorkType = HomeWorkTypes.HOME;
else if (ss == "WORK")
address.HomeWorkType = HomeWorkTypes.WORK;
if (m.Groups["strAttr"].Value == "QUOTED-PRINTABLE")
{
address.POBox = QuotedPrintable.Decode(m.Groups["strPo"].Value);
address.Ext = QuotedPrintable.Decode(m.Groups["strBlock"].Value);
address.Street = QuotedPrintable.Decode(m.Groups["strStreet"].Value);
address.Locality = QuotedPrintable.Decode(m.Groups["strCity"].Value);
address.Region = QuotedPrintable.Decode(m.Groups["strRegion"].Value);
address.Postcode = QuotedPrintable.Decode(m.Groups["strPostcode"].Value);
address.Country = QuotedPrintable.Decode(m.Groups["strNation"].Value);
}
else
{
address.POBox = m.Groups["strPo"].Value;
address.Ext = m.Groups["strBlock"].Value;
address.Street = m.Groups["strStreet"].Value;
address.Locality = m.Groups["strCity"].Value;
address.Region = m.Groups["strRegion"].Value;
address.Postcode = m.Groups["strPostcode"].Value;
address.Country = m.Groups["strNation"].Value;
}
}
}
break;
case "NOTE":
regex = new Regex(regxNote, options);
m = regex.Match(vCardLine);
if (m.Success)
{
if (m.Groups["strAttr"].Value == "QUOTED-PRINTABLE")
v.Note = QuotedPrintable.Decode(m.Groups["strValue"].Value);
else
v.Note = m.Groups["strValue"].Value;
}
break;
case "URL":
regex = new Regex(@"((?<strElement>(URL)) (;*(?<strAttr>(HOME|WORK)))? (:(?<strValue>[^\n\r]*)))", options);
mc = regex.Matches(vCardLine);
if (mc.Count > 0)
{
for (int i = 0; i < mc.Count; i++)
{
URL url = new URL();
v.URLs.Add(url);
m = mc[i];
url.Address = m.Groups["strValue"].Value;
ss = m.Groups["strAttr"].Value;
if (ss == "HOME")
url.HomeWorkTypes = HomeWorkTypes.HOME;
else if (ss == "WORK")
url.HomeWorkTypes = HomeWorkTypes.WORK;
}
}
break;
case "ROLE":
regex = new Regex(regxRole, options);
m = regex.Match(vCardLine);
if (m.Success)
v.Role = m.Groups["strROLE"].Value;
break;
}
}
return v;
}
}
}
with this code
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
namespace aaa
{
public partial class SaveContactPage : PhoneApplicationPage
{
string vcard = "";
SaveContactTask saveContactTask = new SaveContactTask();
public SaveContactPage()
{
InitializeComponent();
saveContactTask.Completed += new EventHandler<SaveContactResult>(saveContactTask_Completed);
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (NavigationContext.QueryString.TryGetValue("vcard", out vcard))
{
TextBox.Text = "";
VCard vc = VCardReader.ParseText(vcard);
saveContactTask.FirstName = vc.GivenName;
saveContactTask.LastName = vc.Surname;
TextBox.Text += "FullName: ";
TextBox.Text += saveContactTask.FirstName + saveContactTask.LastName;
TextBox.Text += Environment.NewLine;
for (int i = 0; i < vc.Phones.Count; i++)
{
//TextBox.Text += "Phone " + vc.Phones[i].PhoneTypes.ToString("G") + " " + vc.Phones[i].HomeWorkTypes.ToString() + (vc.Phones[i].Pref ? "Preferred" : "") + "=" + vc.Phones[i].Number + Environment.NewLine;
if (vc.Phones[i].HomeWorkTypes.ToString() == "None")
{
TextBox.Text += "Mobile Phone: ";
saveContactTask.MobilePhone = vc.Phones[i].Number;
TextBox.Text += saveContactTask.MobilePhone;
TextBox.Text += Environment.NewLine;
}
if (vc.Phones[i].HomeWorkTypes.ToString() == "WORK")
{
TextBox.Text += "Work Phone: ";
saveContactTask.WorkPhone = vc.Phones[i].Number;
TextBox.Text += saveContactTask.WorkPhone;
TextBox.Text += Environment.NewLine;
}
if (vc.Phones[i].HomeWorkTypes.ToString() == "HOME")
{
TextBox.Text += "Home Phone: ";
saveContactTask.HomePhone = vc.Phones[i].Number;
TextBox.Text += saveContactTask.HomePhone;
TextBox.Text += Environment.NewLine;
}
}
for (int i = 0; i < vc.Emails.Count; i++)
{
//TextBox.Text += "Email " + " " + (vc.Emails[i].Pref ? "Preferred" : "") + "=" + vc.Emails[i].Address + Environment.NewLine;
saveContactTask.PersonalEmail = vc.Emails[i].Address;
TextBox.Text += saveContactTask.PersonalEmail;
TextBox.Text += Environment.NewLine;
}
/*
if (!String.IsNullOrEmpty(vc.Prefix))
TextBox.Text += "Prefix=" + vc.Prefix + Environment.NewLine;
if (!String.IsNullOrEmpty(vc.Prefix))
TextBox.Text += "Suffix=" + vc.Suffix+ Environment.NewLine;
if (vc.Birthday > DateTime.MinValue)
TextBox.Text += "Birthday=" + vc.Birthday.ToLongDateString() + Environment.NewLine;
if (vc.Rev != null)
TextBox.Text += "Rev=" + vc.Rev.ToLongDateString()+" "+vc.Rev.ToLongTimeString() + Environment.NewLine;
if (!String.IsNullOrEmpty(vc.Org))
TextBox.Text += "Org=" + vc.Org + Environment.NewLine;
for (int i = 0; i < vc.URLs.Count; i++)
{
TextBox.Text += "URL " + vc.URLs[i].HomeWorkTypes.ToString() + " " + "=" + vc.URLs[i].Address + Environment.NewLine;
}
for (int i = 0; i < vc.Addresses.Count; i++)
{
TextBox.Text += "Address " + vc.Addresses[i].HomeWorkType.ToString() + "=" + vc.Addresses[i].POBox + ","
+ vc.Addresses[i].Ext + ", "
+ vc.Addresses[i].Street + ", "
+ vc.Addresses[i].Locality + ", "
+ vc.Addresses[i].Region + ", "
+ vc.Addresses[i].Postcode + ", "
+ vc.Addresses[i].Country + Environment.NewLine;
}
if (!String.IsNullOrEmpty(vc.Note))
TextBox.Text += "Note="+vc.Note;
TextBox.Text += "=============================" + Environment.NewLine;
*/
}
}
void saveContactTask_Completed(object sender, SaveContactResult e)
{
switch (e.TaskResult)
{
//Logic for when the contact was saved successfully
case TaskResult.OK:
MessageBox.Show("Contact saved.");
break;
//Logic for when the task was cancelled by the user
case TaskResult.Cancel:
MessageBox.Show("Save cancelled.");
break;
//Logic for when the contact could not be saved
case TaskResult.None:
MessageBox.Show("Contact could not be saved.");
break;
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
try
{
saveContactTask.Show();
}
catch (System.InvalidOperationException ex)
{
MessageBox.Show("An error occurred.");
}
}
}
}
hope this helps
回答2:
OK, I found this:
We'll use the WindowsRuntimeStreamExtensions class to convert the System.IO Streams to the Windows.Storage.Streams objects:
System.IO.MemoryStream ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(VCardDataString));
IInputStream input= System.IO.WindowsRuntimeStreamExtensions.AsInputStream(ms);
ContactInformation info = await ContactInformation.ParseVcardAsync(input);
StoredContact phoneContact = new StoredContact(store, info);
来源:https://stackoverflow.com/questions/14961704/windows-phone-parse-a-vcard-string