Применение регулярных выражений для улучшения возможностей функции Split() не дает представления об их настоящей силе. В следующем примере регулярные выражения применяются для анализа файла журнала IIS. Файл журнала выглядит примерно так:
#Software: Microsoft Internet Information Server 4.0
#Version: 1.0
#Date: 1999-12-31 00:01:22
#Fields: time c-ip cs-method cs-uri-stem sc-status
00:01:31 157.56.214.169 GET /Default.htm 304
00:02:55 157.56.214.169 GET /docs/project/overview.htm 200
Следующая программа преобразует файл журнала в более удобный формат.
// Файл: logparse.cs
// Команда компиляции:
// csc logparse.cs /r:system.net.dll /r:system.text.regularexpressions.dll
using System;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Collections;
class Test
{
public static void Main(string[] args)
{
if (args.Length == 0) //Должен быть указан анализируемый файл
{
Console.WriteLine("No log file specified.");
}
else
ParseLogFile(args[0]);
}
public static void ParseLogFile(string filename)
{
if (!System.IO.File.FileExists(filename))
{
Console.WriteLine ("The file specified does not exist.");
}
else
{
FileStream f = new FileStream(filename, FileMode.Open);
StreamReader stream = new StreamReader(f);
string line;
line = stream.ReadLine(); // Строка заголовка
line = stream.ReadLine(); // Строка версии
line = stream.ReadLine(); // Строка даты
Regex regexDate= new Regex(@"\:\s(?<date>[^\s]+)\s");
Match match = regexDate.Match(line);
string date = "";
if (match.Length != 0)
date = match.Group("date").ToString();
line = stream.ReadLine(); // Строка Fields
Regex regexLine =
new Regex( // Последовательность цифр или :
@"(?<time>(\d|\:)+)\s" +
// Последовательность цифр или .
@"(?<ip>(\d|\.)+)\s" +
// Любая комбинация непробельных символов
@"(?<method>\S+)\s" +
// Любая комбинация непробельных символов
@"(?<uri>\S+)\s" +
// Последовательность цифр
@"(?<status>\d+)");
// Последовательно читать строки файла
// Сгенерировать описание для каждой строки
while ((line = stream.ReadLine()) != null)
{
//Console.WriteLine(line);
match = regexLine.Match(line);
if (match.Length != 0)
{
Console.WriteLine("date: {0} {1}", date,
match.Group("time"));
Console.WriteLine("IP Address: {0}",
match.Group("ip"));
Console.WriteLine("Method: {0}",
match.Group("method"));
Console.WriteLine("Status: {0}",
match.Group("status"));
Console.WriteLine("URI: {0}\n",
match.Group("uri"));
}
}
f.Close();
}
}
}
Общая структура программы выглядит знакомо. В этом примере использованы два регулярных выражения. Строка даты и регулярное выражение для ее анализа выглядят так:
#Date: 1999-12-31 00:01:22
\:\s(?<date>[^\s]+)\s
В программе регулярные выражения обычно записываются в виде строк-литералов, поскольку синтаксис регулярных выражений допускает использование служебного префикса \. Чтобы регулярное выражение было проще читать, его разбивают на отдельные элементы. Например, следующая запись совпадает в строке с двоеточием (:):
\:
Обратная косая черта (\) необходима из-за того, что в регулярных выражениях двоеточие обладает самостоятельным смыслом. Метасимвол \s соответствует одному пробельному символу (табуляции или пробелу).
В следующей части выражение ?<date> задает имя переменной, которой будут присвоены совпавшие символы для последующего извлечения:
(?<date>[^\s]+)
Выражение [^\s] называется символьной группой, а символ ^ означает «ни один из следующих символов». Таким образом, эта группа совпадает с любым непробельным символом. Наконец, символ + совпадает с одним или несколькими экземплярами предыдущей спецификации (то есть одним или несколькими непробельными символами). В приведенном примере эта часть выражения совпадает с последовательностью 1999-12-31.
Чтобы поиск давал более точный результат, можно воспользоваться метасимволом \d, соответствующим одной цифре. В этом случае все выражение принимает вид:
\:\s(?<date>\d\d\d\d-\d\d-\d\d)\s
Итак, мы разобрались с простым регулярным выражением. Для анализа строк файла журнала применяется более сложное регулярное выражение. Поскольку строки журнала имеют единый формат, в данном примере можно было воспользоваться функцией Split(), но тогда пример стал бы недостаточно показательным. Регулярное выражение состоит из следующих частей:
(?<time>(\d|\:)+)\s // последовательность цифр или : (время)
(?<ip>(\d|\.)+)\s // последовательность цифр или . (IP-адрес)
(?<method>\S+)\s // любые непробельные символы (метод HTTP)
(?<uri>\S+)\s // любые непробельные символы (URL)
(?<status>\d+) // последовательность цифр (статус)
0 коммент.:
Отправить комментарий