Лучший способ разобрать файл журнала на C #

У меня есть следующий файл журнала:

START:SOME_STRING
BL:2
LK:3
LH:5
end
START:SOME_STRING
BL:5
LK:6
LH:6
end

У которого есть несколько структур START: -> end внутри. Есть ли лучший «небрежный» способ разобрать этот файл, а не читать строку за строкой и использовать SPLIT?


person rvk    schedule 03.11.2010    source источник


Ответы (3)


Вы можете попытаться формализовать грамматику вашего ini-файла, а также некоторые из генераторов парсеров. Дополнительные сведения см. В этом вопросе.

Однако имейте в виду, что для такой простой грамматики, как ваша, может быть проще разобрать вручную :-P

class IniEntry
{
    public int BL;
    public int LK;
    public int LH;
    IniEntry Clone() { return new IniEntry { BL = BL, LK = LK, LH = LH }; }
}

IEnumerable<IniEntry> Parse()
{
    IniEntry ie = new IniEntry();
    while (ParseEntry(out ie))
        yield return ie.Clone();
}

bool ParseEntry(out IniEntry ie)
{
    ie = new IniEntry();
    return ParseStart(ie) &&
               ParseBL(ie) &&
               ParseLK(ie) &&
               ParseLH(ie) &&
               ParseEnd(ie);
}

bool ParseStart(IniEntry ie)
{
    string dummy;
    return ParseLine("START", out dummy);
}

bool ParseBL(IniEntry ie)
{
    string BL;
    return ParseLine("BL", out BL) && int.TryParse(BL, out ie.BL);
}

bool ParseLK(IniEntry ie)
{
    string LK;
    return ParseLine("LK", out LK) && int.TryParse(LK, out ie.LK);
}

bool ParseLH(IniEntry ie)
{
    string LH;
    return ParseLine("LH", out LH) && string.TryParse(LH, out ie.LH);
}

bool ParseLine(string key, out string value)
{
    string line = GetNextLine();
    var parts = line.Split(":");
    if (parts.Count != 2) return false;
    if (parts[0] != key) return false;
    value = parts[1];
}

и Т. Д.

person Vlad    schedule 03.11.2010
comment
Это файл журнала, который мне дали проанализировать, к сожалению, он не подлежит изменению. - person rvk; 03.11.2010
comment
Вам не нужно менять файл журнала, почему? - person Vlad; 03.11.2010

Это хороший кандидат для цикла while и конечного автомата. При таком подходе вы бы использовали даже меньше памяти и имели бы большую производительность, чем при использовании string.split ()

person Karim Agha    schedule 03.11.2010
comment
Некоторые дальнейшие подробности о государственной машине получат от меня положительное голосование. - person Noel Abrahams; 03.11.2010
comment
Государственный аппарат? Я посмотрю на это. - person rvk; 03.11.2010
comment
Избегайте слишком «небрежной» ошибки. Если вы не можете повторно использовать что-то еще, реализацию механизма состояния, вам лучше дважды сделать это, если это сусло. Вы можете сделать вариант SPLIT гораздо быстрее. - person Liviu Mandras; 03.11.2010

Если точно, что НАЧАЛО / КОНЕЦ всегда совпадают (извините, мой C # смущает, так что простой английский):

Read the whole file with System.IO.ReadToEnd
Parse the whole thing in one go with a regular expression
Iterate over regex results

Регулярное выражение будет выглядеть примерно так: «(START: ([^ $] +) $ BL: ([^ $] +) $ LK: ([^ $] +) $ LH: ([^ $] +) $ end $». ) + ", вам нужно будет проверить / отрегулировать в соответствии с тем, как происходят ваши параметры BL / LK и т. д.

person smirkingman    schedule 03.11.2010
comment
Это звучит неэффективно, когда некоторые файлы, которые мне нужно прочитать, имеют размер более 6000 строк. Разве я ошибаюсь? - person rvk; 03.11.2010
comment
Это действительно плохое решение. Только представьте, что файл имеет размер в несколько сотен мегабайт. Лучше читать его построчно (или отрывок за куском) и использовать какой-нибудь конечный автомат. - person Oliver; 03.11.2010
comment
Неужели проблема с памятью? Даже если на мгновение потребуется 1 ГБ памяти, ну и что? Конечно, конечный автомат более элегантен, но это быстро решает проблему. - person smirkingman; 03.11.2010