۱۳۸۷/۰۸/۲۷

استخراج آدرس‌هاي ايميل از يك متن


در قسمت اول بررسي نحوه برنامه نويسي افزونه outlook ، در مورد استفاده از regular expressions اندكي توضيح داده شد. امروز مثالي ديگر از همين دست را بررسي خواهيم كرد.

چند روز قبل يك ايميل تبليغاتي به دست من رسيد كه فرد ارسال كننده انبوهي از ايميل‌ها را در قسمت To قرار داده بود (بجاي قسمت BCC (رونوشت مخفي)).
خوب، براي جدا كردن انبوهي از ايميل‌هاي مخلوط با ساير متون چه بايد كرد؟ چند ساعت وقت گذاشت و تك تك آنها را به صورت دستي جدا كرد؟ (براي ذخيره سازي در يك ديتابيس براي مثال :) )
يا براي مثال برنامه‌هاي download manager توانايي استخراج لينك‌هاي موجود در يك متن كپي شده در حافظه را دارند. آنها به چه صورتي عمل مي‌كنند؟ چگونه مي‌توانند لينك‌ها را با دقتي بالا و بسيار سريع از لابلاي متن موجود تشخيص دهند؟

بهينه‌ترين و سريعترين‌ راه براي اين نوع جستجوها استفاده از كتابخانه regular expressions (عبارات با قاعده) در دات نت فريم ورك است. اگر نياز به يك برگه تقلب (!) در اين زمينه داشتيد مي‌توانيد به اينجا مراجعه كنيد. همچنين در همان سايت، كاربران بسياري را خواهيد يافت كه الگوهاي ابداعي خود را با ديگران به اشتراگ مي‌گذارند.

براي مثال فرض كنيد فايلي را كه حاوي مخلوطي از متن و ايميل است را در يك رشته بارگذاري كرده‌ايد. نحوه استخراج ايميل‌هاي موجود با استفاده از اين امكانات به صورت زير خواهد بود:
using System.IO;
using System.Text.RegularExpressions;
using System.Text;

class CRegEx
{
/// <summary>
/// استخراج ايميل‌هاي يك فايل متني و ذخيره آن در فايلي جديد
/// </summary>
/// <param name="inFilePath">فايل ورودي</param>
/// <param name="outFilePath">فايل خروجي</param>
public static void ExtractEmails(string inFilePath, string outFilePath)
{
string data = File.ReadAllText(inFilePath); //خواندن فايل متني
//ايجاد شيء عبارت با قاعده بر اساس الگوي تشخيص ايميل‌ها
Regex emailRegex = new Regex(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",
RegexOptions.IgnoreCase);
//پيدا كردن گروه تطابق يافته با الگوي ما
MatchCollection emailMatches = emailRegex.Matches(data);
//ايجاد شيء استرينگ بيلدر براي ذخيره سازي سريع اطلاعات دريافتي
StringBuilder sb = new StringBuilder();
//ذخيره ايميل‌هاي استخراج شده
foreach (Match emailMatch in emailMatches)
{
sb.AppendLine(emailMatch.Value);
}
//ذخيره كردن اطلاعات استخراج شده در فايلي جديد
File.WriteAllText(outFilePath, sb.ToString());
}
}

راستي، اگر روزي خواستيد تعداد بالايي ايميل ارسال كنيد، آنها را به قسمت bcc اضافه كنيد (Message.Bcc.Add)، در قالب يك ايميل، نه چند هزار ايميل متوالي (در طي يك حلقه براي مثال). به اين صورت (استفاده از قسمت BCC) ميل سرور تمام آدرس‌ها را در صف قرار خواهد داد و متحمل بار اضافي شديد نخواهد شد. در اين حالت اگر ميل باكس خود را چك كنيد شايد بلافاصله ايميل مورد نظر را دريافت نكنيد. نگران نباشيد، انجام عمليات در صف قرار گرفته و در طي دقايق و يا حتي ساعات بعدي پردازش خواهد شد (بسته به بار سرور).
چند نكته را بايد در اينجا در نظر داشت. حتما آدرس‌هاي اضافه شده را با استفاده از عبارات باقاعده يكبار پيش از اضافه شدن بررسي نمائيد (Regex.IsMatch). در صورتيكه يكي از ايميل‌ها فرمت غيراستانداردي داشته باشد كل كار برگشت خواهد خورد.
و همچنين بايد دقت داشت كه براي اين موضوع حد نصاب وجود دارد. بر روي يكي از ميل سرورهاي يك هاست ايراني تست كردم، حداكثر 100 رونوشت مخفي را بيشتر قبول نمي‌كرد. بنابراين هر بار مي‌شود 100 ايميل را به صورت يكجا ارسال كرد (كه باز هم از روش استفاده از حلقه‌اي كه 100 بار ايميل مي‌زند بسيار بهتر است و هاست دار به علت ايجاد بار اضافي شديد بر روي سرور با شما تماس نخواهد گرفت)