Помимо классов Regex и Match в пространстве имен System.Text.RegularExpressions определены вспомогательные классы, например, класс Capture — фрагмент, совпавший с подвыражением в круглых скобках; класс CaptureCollection — коллекция фрагментов, совпавших со всеми подвыражениями в текущей группе; класс Group содержит коллекцию Capture для текущего совпадения с регулярным выражением и т. д.
В качестве более реального примера применения регулярных выражений рассмотрим программу анализа файла журнала веб-сервера. Это текстовый файл, каждая строка которого содержит информацию об одном соединении с сервером. Четыре строки файла приведены ниже:
ppp-48.pool-113.spbnit.ru - - [31/Мау/2002:02:08:32 +0400] "GET / HTTP/1.1" 200
2434 "http://www.priсе.ru/bin/price/firminfo_f?fid=10922&where=01&base=2"
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
81.24.130.7 - - [31/May/2002:08:13:17 +0400] "GET /swf/menu.swf HTTP/1.1" 200
4682 "-" "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98)"
81.24.130.7 - - [31/May/2002:08:13:17 +0400] "GET /swf/header.swf HTTP/1.1" 200
21244 "-" "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98)"
gate.solvo.ru - - [31/May/2002:10:43:03 +0400] "GET / HTTP/1.0" 200 2422
|
|
"http://www.price.ru/bin/price/firminfo_f?fid=10922&where=01&base=l"
"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"
Подобные файлы могут иметь весьма значительный объем, поэтому составление итогового отчета в удобном для восприятия формате имеет важное значение. Если рассматривать каждую строку файла как совокупность полей, разделенных пробелами, то поле номер 0 содержит адрес, с которого выполнялось соединение с сервером, поле номер 5 — операцию (GET при загрузке информации), поле 8 — признак успешности выполнения операции (200 — успешно) и, наконец, поле 9 — количество переданных байтов.
Приведенная в листинге 15.6 программа формирует в формате HTML итоговый отчет, содержащий таблицу адресов, с которых выполнялось обращение к серверу, и суммарное количество переданных байтов для каждого адреса.
Листинг 15.6. Анализ журнала веб-сервера
using System;
using System.Text.RegularExpressions;
using System;
using System.IO;
using System.Collections.Generiс;
using System.Text.RegularExpressions;
public class Test
{
public static void Main()
{
StreamReader f = new StreamReader("access_log");
StreamWriter w = new StreamWriter("report.htm");
Regex get = new Regex("GET");
Regex r = new Regex(" ");
string s, entry;
int value;
string[] items = new string[40];
Dictionary<string, int> table = new Dictionary<string, int>();
while ((s = f.ReadLine())!= null)
{
items = r.Split(s);
if (get.IsMatch(items[5]) && items[8] == "200")
{
entry = items[0];
value = int.Parse(items[9]);
if (table.ContainsKey(entry))
table[entry] += value;
else
table[entry] = value;
}
}
f.Close();
w.Write("<html><head><title> Report </title></head><body>" +
"<table border =1 <tr><td> Computer <td> Bytes </tr>");
foreach (string item in table.Keys)
w.Write("<tr><td>{0}<td>{l}</tr>", item, table[item]);
w.Write("</table></body>");
w.Close();
}
}
Фрагмент результата работы программы показан на рис. 15.1.
|
|
Computer | Bytes |
ppp-48.pool-113.spbnit.ru | |
test223.sovam.com | |
210.82 124 83 | |
ipblock209-209-002.octetgroup.net | |
81.24.130.7 | |
gate.solvo.ru | |
212.113.108.164 |
Рис. 15.1. Фрагмент журнала веб-сервера
Файл access_log считывается построчно, каждая строка разбивается на поля, которые заносятся в массив items. Затем, если загрузка прошла успешно, о чем свидетельствуют значения GET и 200 полей 5 и 8, количество переданных байтов (поле 9) преобразуется в целое и заносится в хеш-таблицу по ключу, которым служит адрес, хранящийся в поле 0.
Для формирования HTML-файла report.htm используются соответствующие теги. Файл можно просмотреть, например, с помощью Internet Explorer. Как видите, программа получилась весьма компактной за счет использования стандартных классов библиотеки.NET (справедливости ради надо отметить, что аналогичная программа на языке Perl примерно в два раза короче).