Разбор в C # со словарем - PullRequest
4 голосов
/ 19 мая 2011

Я новичок в программировании и очень стараюсь разобрать файл.Сначала я пытался разобрать его определенным образом, но это не сработало правильно.Я хочу проанализировать следующую строку в словаре <строка, строка>.

Сетевая карта (ы): 7 сетевых карт установлено.

                       [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 в качестве значения и так далее для остальных шести.Спасибо за помощь.Действительно ценю это.Любая помощь в том, как это сделать, будет великолепна, поскольку я схожу с ума, читая о разбиении строк и пытаясь понять, как получить словарь для хранения значения.

Ответы [ 6 ]

3 голосов
/ 19 мая 2011

Вот решение, которое не использует регулярные выражения, если вы не хотите идти по этому пути. Этот код был протестирован.

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; }
        }
    }
}
2 голосов
/ 19 мая 2011

Простите за плохой синтаксис C # - я привык к VB .NET. Не смейся.

Сначала я прочитал бы строки текста файла в массив строк.

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

}

Для каждой строки вы находитесь либо в строке «ключ», либо в строке «значение». Ключевые строки выглядят так:

[01]: Broadcom

Чтобы определить, находитесь ли вы в «ключевой» строке, вы можете попробовать что-то вроде line.Trim().StartsWith("["), но это не сработает надежно, потому что у вас есть другие строки, похожие на [01]: abc.def.ghi.jkl, которые являются IP-адресами, и не ключи. Поэтому вам нужно быть немного умнее и, возможно, даже использовать регулярное выражение, чтобы определить, смотрите ли вы на IP-адрес или сетевую карту. Я не знаю точных спецификаций файла, который вы просматриваете, но вы также можете использовать начальные пробелы / табуляции, чтобы определить, находитесь ли вы в строке «ключ» или «значение».

Ваш код будет выглядеть примерно так:

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() + " ";
  }
}

Необходимо написать метод IsKeyLine, и это суть всей операции. Вот пример метода, основанного на регулярных выражениях, который вы можете использовать:

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;
}

Теперь я не потратил время на тестирование любого из этого кода - это не в моей голове. Но это должно по крайней мере заставить вас двигаться в общем правильном направлении. Самая большая вещь, которую нужно определить - это стандарт для формата файла. Это даст вам подсказки, чтобы идти по правильному пути. Возможно, вам даже не понадобятся регулярные выражения (что было бы предпочтительнее, поскольку регулярные выражения обычно дороги в запуске).

1 голос
/ 19 мая 2011

Вы также можете сосчитать табуляцию / пробелы в начале каждой строки, указывая, где эта строка принадлежит.

0 голосов
/ 29 ноября 2014

Может быть проще, если вы поместите его в вывод CSV.

Systeminfo /fo csv
0 голосов
/ 19 мая 2011

Я знаю, что этот вопрос касается C #, а не powershell , и уже есть несколько хороших ответов на C #, но я бы хотел предложить решение powershell , так как что-то рассмотреть. Может оказаться проще, чем код на 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), вы можете просто открыть его и вставить приведенный выше код в командную строку, и вы сразу сможете увидеть результат.

0 голосов
/ 19 мая 2011

Подумайте об использовании ведущего пробела , чтобы определить «роль», которую играет линия (эй, 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"
        }
    }
}
...