簡體   English   中英

使用C#Dictionary解析日志文件

[英]Using C# Dictionary to parse log file

我正在嘗試解析一個相當長的日志文件,並創建一個更易於管理的問題列表。

我能夠逐行讀取和解析單個日志,但我需要做的是只顯示唯一條目,因為有些錯誤比其他錯誤更頻繁地出現,並且總是用相同的文本記錄。

我要嘗試做的是創建一個Dictionary對象來保存每個唯一的條目,當我處理日志文件時,搜索Dictionary對象以查看是否已經存在相同的值。

這是我所擁有的代碼的原始樣本(正在進行的工作,我希望我的所有語法都正確),但這些代碼不起作用。 由於某種原因,此腳本永遠不會看到任何不同的條目(如果語句從未通過):

    string[] rowdta = new string[4];
    Dictionary<string[], int> dict = new Dictionary<string[], int>();
    int ctr = -1;
    if (linectr == 1)
        {
            ctr++;
            dict.Add(rowdta, ctr);
        }
        else
        {
            foreach (KeyValuePair<string[], int> pair in dict)
            {
                if ((pair.Key[1] != rowdta[1]) || (pair.Key[2] != rowdta[2])| (pair.Key[3] != rowdta[3]))
                {
                    ctr++;
                    dict.Add(rowdta, ctr);
                }
            }
        }

一些樣本數據:第一行

    rowdta[0]="ErrorType";
    rowdta[1]="Undefined offset: 0";
    rowdta[2]="/url/routesDisplay2.svc.php";
    rowdta[3]="Line Number 5";

第二行

    rowdta[0]="ErrorType";
    rowdta[1]="Undefined offset: 0";
    rowdta[2]="/url/routesDisplay2.svc.php";
    rowdta[3]="Line Number 5";

第3行

    rowdta[0]="ErrorType";
    rowdta[1]="Undefined variable: fvmsg";
    rowdta[2]="/url/processes.svc.php";
    rowdta[3]="Line Number 787";

因此,有了這個,字典中將包含2個項目,第一行和第三行。

我也嘗試過以下內容,nalso在日志文件文本中找不到任何變化。

    if (!dict.ContainsKey(rowdta)) {}

有人可以幫我解決這個語法嗎? 我只是C#的新手,但這應該是相對簡單的。 和往常一樣,我認為這應該是足夠的信息來開始對話。 如果您需要/需要更多細節,請告訴我。

您看到問題的原因是字符串數組不能用作字典中的鍵而不提供自定義IEqualityComparer<string[]>或在其周圍編寫包裝器。

編輯這是一個快速而又臟的自定義比較器實現:

private class ArrayEq<T> : IEqualityComparer<T[]> {
    public bool Equals(T[] x, T[] y) {
        return x.SequenceEqual(y);
    }
    public int GetHashCode(T[] obj) {
        return obj.Sum(o => o.GetHashCode());
    }
}

以下是如何使用它:

var dd = new Dictionary<string[], int>(new ArrayEq<string>());
dd[new[] { "a", "b" }] = 0;
dd[new[] { "a", "b" }]++;
dd[new[] { "a", "b" }]++;
Console.WriteLine(dd[new[] { "a", "b" }]);

為字符串創建一個實現IEquatable的包裝器。

public class LogFileEntry :IEquatable<LogFileEntry>
{
    private readonly string[] _rows;

    public LogFileEntry(string[] rows)
    {
        _rows = rows;
    }

    public override int GetHashCode()
    {
        return 
            _rows[0].GetHashCode() << 3 | 
            _rows[2].GetHashCode() << 2 | 
            _rows[1].GetHashCode() << 1 | 
            _rows[0].GetHashCode();
    }

    #region Implementation of IEquatable<LogFileEntry>

    public override bool Equals(Object obj)
    {
        if (obj == null) 
            return base.Equals(obj);

        return Equals(obj as LogFileEntry);  
    } 

    public bool Equals(LogFileEntry other)
    {
        if(other == null) 
            return false;

        return _rows.SequenceEqual(other._rows);
    }

    #endregion
}

然后在你的字典中使用它:

var d = new Dictionary<LogFileEntry, int>();

var entry = new LogFileEntry(rows);
if( d.ContainsKey(entry) )
{
    d[entry] ++;
} 
else
{
    d[entry] = 1;
}

或者創建一個類似於@dasblinkenlight提出的自定義比較器,並按如下方式使用

public class LogFileEntry 
{
}

public class LogFileEntryComparer : IEqualityComparer<LogFileEntry>{ ... }

var d = new Dictionary<LogFileEntry, int>(new LogFileEntryComparer());

var entry = new LogFileEntry(rows);
if( d.ContainsKey(entry) )
{
    d[entry] ++;
} 
else
{
    d[entry] = 1;
}

問題是數組相等是引用相等。 換句話說,它不依賴於存儲在數組中的值,它僅取決於數組的標識。

一些解決方案

  • 使用Tuple來保存行數據
  • 使用匿名類型來保存行數據
  • 創建一個自定義類型來保存行數據,如果是類,則重寫Equals和GetHashCode。
  • 創建IEqualityComparer的自定義實現,以根據數組的值比較數組,並在創建時將其傳遞給字典。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM