简体   繁体   English

使用Dictionary <string,string>在C#中进行解析

[英]Parse in C# with Dictionary<string, string>

I am new to programming and have been trying hard to parse a file. 我是编程新手,一直在努力解析文件。 I, initially was trying to parse it in a certain way, but that didn't end up working correctly. 我,最初是试图以某种方式解析它,但这并没有最终正常工作。 I want to parse the following line in a Dictionary< string,string> . 我想解析Dictionary <string,string>中的以下行。

Network Card(s): 7 NIC(s) Installed. 网卡:已安装7个NIC。

                       [01]: Broadcom 
                             Connection Name: Local Area Connection
                             DHCP Enabled:    No
                             IP address(es)
                             [01]: abc.de.xyz.
                       [02]: Broadcom 
                             Connection Name: eth1
                             Status:          Media disconnected
                       [03]: Broadcom 
                             Connection Name: eth0
                             Status:          Media disconnected
                       [04]: Broadcom 
                             Connection Name: eth3
                             Status:          Media disconnected
                       [05]: Mellanox 
                             Connection Name: Local Area Connection 5
                             Status:          Hardware not present
                       [06]: Mellanox 
                             Connection Name: Local Area Connection 6
                             Status:          Media disconnected
                       [07]: Mellanox 
                             Connection Name: Local Area Connection 7
                             DHCP Enabled:    No
                             IP address(es)
                             [01]: mno.pqr.stu.vwx

I want [01] Broadcom as the key to the dictionary and Connection Name: Local Area Connection DHCP Enabled: No IP address(es) [01]: abc.de.xyz as the value and so on for the other six. 我希望[01] Broadcom作为字典和连接名称的关键:本地连接DHCP启用:无IP地址[01]:abc.de.xyz作为其他六个的值,依此类推。 Thanks for the help. 谢谢您的帮助。 Really appreciate it. 真的很感激。 Any help on how to go about doing it will be great since I have gone crazy reading about splitting strings and trying to figure out how to get the dictionary to store the value. 任何关于如何去做的帮助都会很棒,因为我疯狂阅读有关分割字符串并试图找出如何获取字典来存储值的信息。

Here is a solution that does not use regex if you don't want to take that route. 如果您不想使用该路由,这是一个不使用正则表达式的解决方案。 This code has been tested. 此代码已经过测试。

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

namespace NicParser
{
    public class NicFileParser
    {
        private readonly string _file;
        private readonly Dictionary<string, string> _nics;

        public NicFileParser(string file)
        {
            _file = file;
            _nics = new Dictionary<string, string>();
        }

        public void Parse()
        {
            var key = string.Empty;
            var value = new StringBuilder();

            try
            {
                using (var rdr = new StreamReader(_file))
                {
                    var firstTime = true;

                    while (rdr.Peek() > 0)
                    {
                        var line = rdr.ReadLine().Trim();

                        if (IsKey(line))
                        {
                            // Once a key is hit, add the previous 
                            // key and values (except the first time).
                            if (!firstTime)
                            {
                                _nics.Add(key, value.ToString());
                            }
                            else
                            {
                                firstTime = false;
                            }

                            // Assign the key, and clear the previous values.
                            key = line;
                            value.Length = 0;
                        }
                        else
                        {
                            // Add to the values for this nic card.
                            value.AppendLine(line);
                        }
                    }

                    // Final line of the file has been read. 
                    // Add the last nic card.
                    _nics.Add(key, value.ToString());
                }
            }
            catch (Exception ex)
            {
                // Handle your exceptions however you like...
            }
        }

        private static bool IsKey(string line)
        {
            return (!String.IsNullOrEmpty(line)
                 && line.StartsWith("[") 
                 && !line.Contains("."));
        }

        // Use this to access the NIC information.
        public Dictionary<string, string> Cards
        {
            get { return _nics; }
        }
    }
}

Forgive any poor C# syntax - I'm used to VB .NET. 原谅任何可怜的C#语法 - 我已经习惯了VB .NET。 Don't laugh. 不要笑。

I would read the file's lines of text into a string array first. 我会首先将文件的文本行读入字符串数组。

foreach (string line in File.ReadLines("path-to-file")) {

}

For each line, you're either on a "key" line or a "value" line. 对于每一行,您要么处于“关键”行,要么处于“值”行。 Key lines look like this: 关键线看起来像这样:

[01]: Broadcom

To determine if you are on a "key" line, you could try something like line.Trim().StartsWith("[") , but that won't work reliably because you've got other lines which look like [01]: abc.def.ghi.jkl which are IP addresses, and are not keys. 要确定你是否在“关键”行,你可以尝试类似line.Trim().StartsWith("[") ,但是这将无法可靠地工作,因为你有其他行看起来像[01]: abc.def.ghi.jkl是IP地址,不是密钥。 So you need to be a little smarter about it and possibly even use a regular expression to detect if you are looking at an IP address or a network card. 所以你需要对它有点聪明,甚至可能使用正则表达式来检测你是在查看IP地址还是网卡。 I don't know the exact specifications of the file you are looking at, but you also could use the leading spaces/tabs to help you determine whether or not you are on a "key" or a "value" line. 我不知道您正在查看的文件的确切规格,但您也可以使用前导空格/标签来帮助您确定您是否处于“键”或“值”行。

Your code would then look something like this: 您的代码看起来像这样:

var networkCards = new Dictionary<String, String>();
string currentKey = String.Empty;

foreach (string line in File.ReadLines("path-to-file")) {
  if ( IsKeyLine( line ) ) {
    currentKey = line.Trim();
    networkCards.Add(currentKey, "");
  } else {
    networkCards[currentKey] += line.Trim() + " ";
  }
}

The IsKeyLine method would need to be written, and is the crux of the whole operation. 需要编写IsKeyLine方法,这是整个操作的关键。 Here's a stab at a regular expression based method you might use: 这是你可能使用的基于正则表达式的方法的一个刺:

public bool IsKeyLine(string line) {
  if (!String.IsNullOrEmpty(line)) {
    //run two regexes - one to see if the line is of the general pattern of a "key" line
    //the second reg ex makes sure there isn't an ip address in the line, which would indicate that the line is part of the "value" and not the "key"
    return System.Text.RegularExpressions.RegEx.IsMatch(line, @"^\s*\[\d{0,2}\]: ")
      && !System.Text.RegularExpressions.RegEx.IsMatch(line, @"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}");
  }

  return false;
}

Now, I did not take the time to test any of this code - this is off the top of my head. 现在,我没有花时间测试任何这些代码 - 这是我的头脑。 But it should at least get you going in the general right direction. 但至少应该让你朝着正确的方向前进。 The biggest thing to determine is the standard for the file format though. 确定最重要的是文件格式的标准。 That will give you clues to go down the right path. 这将为您提供走正确道路的线索。 You might not even need regular expressions (which would be preferable, since regex's are typically expensive to run). 您可能甚至不需要正则表达式(这是更可取的,因为正则表达式通常很昂贵)。

您还可以计算每行开头的制表符/空格,指示该行所属的位置。

如果你把它放在csv输出中可能会更容易。

Systeminfo /fo csv

Consider utilizing the leading white space to determine the "role" the line plays (hey, Python does ;-). 考虑利用领先的空白区域来确定线路所扮演的“角色”(嘿,Python确实如此;-)。 Then the file can be parsed line-by-line using a simple state machine. 然后可以使用简单的状态机逐行解析文件。

I suspect that, since this is generated output, this method can be used reliably. 我怀疑,由于这是生成输出,因此可以可靠地使用此方法。 If this is the case, it greatly simplifies the rules and parsing. 如果是这种情况,它会极大地简化规则和解析。

Happy coding. 快乐的编码。


Here is a small proof-of-concept to determine the "role" of the line. 这是一个确定线的“角色”的小概念验证。

using (var inp = ...) {
    string line;
    while ((line = inp.ReadLine()) != null) {
        // normalize to our world of 8-space tabs                        
        line = line.Replace("\t", "        ");
        var lineDepth = line.Length - line.TrimStart().Length;
        if (lineDepth < 65) {
            // is potential "heading line"
        } else { // >= 65
            // is "property line"
        }
    }
}

I know, that this question is about C#, not about powershell , and there are already a few good C# answers, still I would like to contribute a powershell solution, as something to consider. 我知道,这个问题是关于C#,而不是关于PowerShell ,并且已经有一些很好的C#答案,我仍然想提供一个PowerShell解决方案,作为需要考虑的事情。 It can turn out to be simpler than c# code, but this depends on the point of view: 它可以比c#代码更简单,但这取决于观点:

$networkCards = systeminfo | ForEach-Object {$a=0} {
    if ($_.startswith("Network Card(s)")) {$a=1} else {if ($a) {$_}}
}

$networkCards | ForEach-Object {$data=@{}} { 
    if ($_.trim().startswith("[")) {
        $c = $_.trim(); $data[$c] = @()} else {$data[$c] += $_.trim()
    } 
}

#Now we have a hash table with the keys as requested in the question 
#and the values are lists of separate strings, but those can be easily 
#concatenated if needed. Let's display it:
$data

If you have powershell installed (It's part of Windows 7 now) you just can open it and paste the above code at the command prompt and you will be able immediately to see the result. 如果您安装了powershell (它现在是Windows 7的一部分),您只需打开它并在命令提示符下粘贴上面的代码,您就可以立即看到结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM