Разбор файла журнала, неоднозначный разделитель - PullRequest
0 голосов
/ 22 мая 2019

Я должен разобрать файл журнала и не уверен, как лучше взять разные части каждой строки. Проблема, с которой я сталкиваюсь, заключается в том, что оригинальный разработчик использовал ':' для разграничения токенов, что было немного идиотским, поскольку строка содержит метку времени, которая сама содержит ':'!

Пример строки выглядит примерно так:

transaction_date_time:[systemid]:sending_system:receiving_system:data_length:data:[ws_name]

2019-05-08 15:03:13:494|2019-05-08 15:03:13:398:[192.168.1.2]:ABC:DEF:67:cd71f7d9a546ec2b32b,AACN90012001000012,OPNG:[WebService.SomeName.WebServiceModule::WebServiceName]

У меня нет проблем с чтением файла журнала и доступом к каждой строке, но я не знаю, как разобрать фрагменты?

Ответы [ 2 ]

0 голосов
/ 22 мая 2019

Поскольку входная строка не совсем splittable , поскольку разделитель char также является частью содержимого, вместо него можно использовать простое выражение регулярного выражения.
Простое, но, вероятно, достаточно быстрое, даже снастройки по умолчанию.

Различные части входной строки можно разделить с помощью этих групп захвата:

string pattern = @"^(.*?)\|(.*?):\[(.*?)\]:(.*?):(.*?):(\d+):(.*?):\[(.*)\]$";

Это даст вам 8 групп + 1 (Group[0]), которая содержит всю строку.

Используя класс Regex , просто передайте строку для анализа (с именем line, здесь) и регулярное выражение (с именем pattern) в Match () метод, используя настройки по умолчанию:

var result = Regex.Match(line, pattern);

Свойство Groups.Value возвращает результат каждой группы захвата.Например, две даты:

var dateEnd = DateTime.ParseExact(result.Groups[1].Value, "yyyy-MM-dd hh:mm:ss:ttt", CultureInfo.InvariantCulture),
var dateStart = DateTime.ParseExact(result.Groups[2].Value, "yyyy-MM-dd hh:mm:ss:ttt", CultureInfo.InvariantCulture),

IpAddress извлекается с помощью: \[(.*?)\].
Вы можете дать имя этой группе, чтобы было более понятно, к какому значению относится.Просто добавьте строку с префиксом ? и заключенную в <> или в одинарные кавычки ', чтобы назвать группу:

...\[(?<IpAddress>.*?)\]...

Обратите внимание, однако, что присвоение имени группе изменит Regex.Groupsиндексация: вначале будут вставлены неназванные группы, затем именованные группы.Таким образом, присвоение имени только группе IpAddress сделает ее последним элементом Groups[8].Конечно, вы можете назвать все группы, и индексирование будет сохранено.

var hostAddress = IPAddress.Parse(result.Groups["IpAddress"].Value);

Этот шаблон должен позволять машине medium анализировать 130,000~150,000 строк в секунду.
Вам придется проверить его, чтобы найти perfect шаблон.Например, первое совпадение (соответствующее первому свиданию): (.*?)\|, намного быстрее, если не жадное (с использованием ленивого квантификатора).Противоположность последнего матча: \[(.*)\].Шаблон, используемый jdweng , даже быстрее, чем используемый здесь.

См. Regex101 для подробного описания использования и значения каждого токена.

0 голосов
/ 22 мая 2019

Используя Regex, я смог разобрать все. Похоже, что данные пришли из Excel, потому что фракция секунд имеет двоеточие вместо точки. C # не любит двоеточие, поэтому мне пришлось заменить двоеточие точкой. Я также разобрал справа налево, чтобы обойти проблемы толстой кишки.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;


namespace ConsoleApplication3
{
    class Program1
    {
        const string FILENAME = @"c:\temp\test.txt";
        static void Main(string[] args)
        {
            string line = "";
            int rowCount = 0;
            StreamReader reader = new StreamReader(FILENAME);
            string pattern = @"^(?'time'.*):\[(?'systemid'[^\]]+)\]:(?'sending'[^:]+):(?'receiving'[^:]+):(?'length'[^:]+):(?'data'[^:]+):\[(?'ws_name'[^\]]+)\]";

            while ((line = reader.ReadLine()) != null)
            {
                line = line.Trim();
                if (line.Length > 0)
                {
                    if (++rowCount != 1) //skip header row
                    {
                        Log_Data newRow = new Log_Data();
                        Log_Data.logData.Add(newRow);
                        Match match = Regex.Match(line, pattern, RegexOptions.RightToLeft);

                        newRow.ws_name = match.Groups["ws_name"].Value;
                        newRow.data = match.Groups["data"].Value;
                        newRow.length = int.Parse(match.Groups["length"].Value);
                        newRow.receiving_system = match.Groups["receiving"].Value;
                        newRow.sending_system = match.Groups["sending"].Value;
                        newRow.systemid  = match.Groups["systemid"].Value;
                        //end data is first then start date is second
                        string[] date = match.Groups["time"].Value.Split(new char[] {'|'}).ToArray();
                        string replacePattern = @"(?'leader'.+):(?'trailer'\d+)";
                        string stringDate = Regex.Replace(date[1], replacePattern, "${leader}.${trailer}", RegexOptions.RightToLeft);
                        newRow.startDate = DateTime.Parse(stringDate);
                        stringDate = Regex.Replace(date[0], replacePattern, "${leader}.${trailer}", RegexOptions.RightToLeft);
                        newRow.endDate = DateTime.Parse(stringDate );
                    }
                }
            }


        }
    }
    public class Log_Data
    {
        public static List<Log_Data> logData = new List<Log_Data>();

        public DateTime startDate { get; set; } //transaction_date_time:[systemid]:sending_system:receiving_system:data_length:data:[ws_name]
        public DateTime endDate { get; set; }
        public string systemid { get; set; }
        public string sending_system { get; set; }
        public string receiving_system { get; set; }
        public int length { get; set; }
        public string data { get; set; }
        public string ws_name { get; set; }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...