用C#和字典解析<;字符串,字符串>;

用C#和字典解析<;字符串,字符串>;,c#,.net,text-parsing,C#,.net,Text Parsing,我是编程新手,一直在努力解析文件。一、 起初,我们试图以某种方式解析它,但最终无法正常工作。我想解析字典中的以下行 网卡:已安装7个NIC [01]: Broadcom Connection Name: Local Area Connection DHCP Enabled: No

我是编程新手,一直在努力解析文件。一、 起初,我们试图以某种方式解析它,但最终无法正常工作。我想解析字典中的以下行

网卡:已安装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
我希望[01]Broadcom作为字典的键,连接名称:局域网连接DHCP已启用:无IP地址[01]:abc.de.xyz作为其他六个的值,依此类推。谢谢你的帮助。非常感谢。任何关于如何进行这项工作的帮助都将非常有用,因为我已经疯狂地阅读了关于拆分字符串的书籍,并试图找出如何让字典存储值。

请原谅任何糟糕的C#语法-我已经习惯了VB.NET。别笑

我会先将文件的文本行读入字符串数组

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

}
对于每一行,您要么在“关键”行,要么在“价值”行。关键行如下所示:

[01]: Broadcom
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() + " ";
  }
}
要确定您是否在“关键”行上,您可以尝试类似于
line.Trim().StartsWith(“[”
)的操作,但这无法可靠地工作,因为您还有其他类似
[01]的行:abc.def.ghi.jkl
哪些是IP地址,而不是密钥。因此,您需要更聪明一点,甚至可以使用正则表达式来检测您是否正在查看IP地址或网卡。我不知道您正在查看的文件的确切规格,但您也可以使用前导空格/制表符来帮助您确定您是在“关键”行还是在“价值”行

您的代码将如下所示:

[01]: Broadcom
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() + " ";
  }
}
现在,我没有花时间测试任何代码-这是我的想法。但它至少应该让您朝着正确的方向前进。但最需要确定的是文件格式的标准。这将为您提供正确路径的线索。您甚至可能不需要正则表达式(这是最好的,因为正则表达式的运行成本通常很高)。

考虑利用前导空格来确定行所扮演的“角色”(嘿,Python;-)。然后可以使用简单的状态机逐行解析文件

我怀疑,由于这是生成的输出,所以该方法可以可靠地使用。如果是这样,它将大大简化规则和解析

快乐编码


这里是一个小的概念证明,以确定该行的“角色”

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"
        }
    }
}
使用(var inp=…){
弦线;
而((line=inp.ReadLine())!=null){
//标准化为我们的8空间标签世界
行=行。替换(“\t”和“);
var lineDepth=line.Length-line.TrimStart().Length;
如果(线深<65){
//是潜在的“航向线”
}否则{/>=65
//是“建筑红线”
}
}
}

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

如果您不想使用正则表达式,这里有一个解决方案。此代码已经过测试

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; }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用系统文本;
名称空间语法分析器
{
公共类文件解析器
{
私有只读字符串\u文件;
专用只读词典;
公共文件分析器(字符串文件)
{
_文件=文件;
_nics=新字典();
}
公共空解析()
{
var key=string.Empty;
var值=新的StringBuilder();
尝试
{
使用(var rdr=newstreamreader(_文件))
{
var firstTime=true;
而(rdr.Peek()>0)
{
var line=rdr.ReadLine().Trim();
if(IsKey(行))
{
//按下一个键后,添加上一个
//键和值(第一次除外)。
如果(!第一次)
{
_添加(key,value.ToString());
}
其他的
{
第一次=错误;
}
//指定键,然后清除以前的值。
键=行;
值。长度=0;
}
其他的
{
//添加到此nic卡的值。
值。追加行(行);
}
}
//文件的最后一行已被读取。
//添加最后一个nic卡。
_添加(key,value.ToString());
}
}
捕获(例外情况除外)
{
//不管你怎么处理你的异常。。。
}
}
专用静态bool IsKey(字符串行)
{
返回(!String.IsNullOrEmpty(行)
&&行。以(“[”)开头
&&!line.Contains(“.”);
}
//使用此选项可访问NIC信息。
公共字典卡
{
获取{return\u nics;}
}
}
}

< /代码> 我知道,这个问题是关于c*,而不是关于<强> PopeStult,并且已经有一些很好的C语言答案,我仍然想贡献一个<强> PuthSu壳解决方案,作为一个需要考虑的问题。它可以比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
如果您安装了powershell(它现在是Windows 7的一部分),您只需打开它并在命令提示下粘贴上面的代码即可