Получить конкретную строку из определенного блока - PullRequest
7 голосов
/ 29 мая 2020

Я новичок в c#. У меня есть текстовый файл с данными, но я хочу прочитать данные конкретной строки блока.

Здесь адрес может встречаться несколько раз в текстовом файле.

Something here...
... ... ...  
    interface "system"
        address 10.4.1.10/32       
        no shutdown
    exit
something here...
... ... ...
    address 101.4.1.11/32

, но я хочу захватить в этом

interface "system"
        address 10.4.1.10/32       
        no shutdown
    exit

Я хочу захватить этот ip из блока:

10.4.1.10

Я пробовал этот код:

int counter = 0;
string line;
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");
while((line = file.ReadLine()) != null)
{
   Console.WriteLine (line);
   counter++;
}
file.Close();
// Suspend the screen.
Console.ReadLine();

Ожидаемый результат:

Мой ожидаемый результат - захват IP-адреса из этого блока ie .10.4.1.10, что ip находится внутри блока «интерфейсной системы» .. что делает это адрес такой же уникальный .. как может быть много IP-адресов с адресом ключевого слова. Итак, я хочу взять адрес, который находится внутри системного блока интерфейса.

Пожалуйста, дайте мне знать, как я могу захватить конкретную строку из блока.

Ответы [ 4 ]

7 голосов
/ 01 июня 2020

Регулярные выражения идеально подходят для решения этого типа "проблем". Следующее консольное приложение демонстрирует, как использовать Regex для извлечения желаемого IP-адреса из целевого строкового блока.

        private static readonly string IPV4_PATTERN = "[0-9./]";
        private static readonly string IPV4_IPV6_PATTERN = "[A-Z0-9:./]";

        static void Main(string[] args)
        {
            TestSearchFile();
        }



        private static string ParseIpWithRegex(string textToSearch, string startBlock, string endBlock)
        {
            var pattern = $@"{startBlock}\D*\s*({IPV4_IPV6_PATTERN}+).*{endBlock}";
            var ms = Regex.Match(textToSearch, pattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
            if (ms.Groups.TryGetValue("1", out var g))
            {
                return g.Value;
            }

            return string.Empty;
        }



        private static void TestSearchFile()
        {
            var sep = Environment.NewLine;

            var ipAddress6 = "2001:db8:85a3:8d3:1319:8a2e:370:7348";
            var ipAddress4 = "10.4.1.10/32";

            var t = "Something here..." + sep;
            t += "... ... ... " + sep;
            t += "interface \"system\"" + sep;
            t += "address " + ipAddress4 + sep;
            t += "no shutdown" + sep;
            t += "exit" + sep;
            t += "something here..." + sep;
            t += "address 101.4.1.11/32" + sep;
            t += "... ... ... " + sep;

            var startBlock = "interface \"system\"";
            var endBlock = "exit";

            var ip = ParseIpWithRegex(t, startBlock, endBlock);
            Console.WriteLine($"IP: {ip}");
        }

Я включил два шаблона IP-адресов IPV4_PATTERN только для IPV4, а также IPV4_IPV6_PATTERN для IPV4 и IPV6. Выберите тот, который вам больше всего подходит. Хотя IPV4_IPV6_PATTERN будет применяться к обеим версиям IP, я считаю, что это немного улучшает производительность, когда поиск сужается за счет использования самого узкого шаблона.

Не забудьте импортировать ссылку Regex:

using System.Text.RegularExpressions;


Код объяснен

Метод «ParseIpWithRegex» использует шаблон Regex, построенный с использованием строки, обозначающей начало целевой блок и строка, обозначающая конец этого блока. Внутри этого шаблона находится определение класса регулярных выражений, которое определяет шаблон IP-адреса, который мы будем sh изолировать как группу.

$@"{startBlock}\D*\s*({IPV4_IPV6_PATTERN}+).*{endBlock}";

Следует отметить, что фигурные скобки предназначены только для интерполяции строк и не имеют (в данном случае) ничего общего с фактическим регулярным выражением!

После «startBlock» мы видим «\ D *». Это означает, что после «startBlock» включить в поиск все нечисловые c символы (где «звездочка» означает ожидание от нуля до бесконечного числа). Затем мы видим «\ s *», что означает включение всех пробелов (включая символы новой строки, поскольку я включил RegexOptions.Singleline).

Шаблон IP-адреса заключен в скобки «()», что дает команду Regex создавать группы. В этом случае за шаблоном IP-адреса (в приведенном выше примере кода IPV4_IPV6_PATTERN) стоит символ «+». Это указывает на то, что ДОЛЖЕН быть хотя бы один из символов, которые есть в определении класса Regex IP-адреса, чтобы считаться "совпадением".

После этого мы видим ". *" Перед "endBlock". Это означает поиск любого символа - включая символ «новой строки» (от нуля до бесконечного числа) в строке «endBlock».

Если у вас есть какие-либо вопросы, оставьте комментарий.



ИЗМЕНИТЬ

С помощью метода кнопки onclick вы вызовете SearchFileForIp. Вам нужно будет изменить myTextBox в соответствии с вашим кодом.

Вы также должны решить, будете ли вы искать IPV4 или оба IPV4 и IPV6, и выберите соответствующую переменную IPV4_PATTERN или IPV4_IPV6_PATTERN.

    private void SearchFileForIp()
    {
        var fileName = "c:\\test.txt";
        using var sr = new StreamReader(fileName);
        string fileContent = sr.ReadToEnd();

        var startBlock = "interface \"system\"";
        var endBlock = "exit";

        var ip = ParseForIpRegex(fileContent, startBlock, endBlock);
        myTextBox.Text = ip; //Change this to match your code
    }


    private readonly string IPV4_PATTERN = "[0-9./]";
    private readonly string IPV4_IPV6_PATTERN = "[A-Z0-9:./]";
    private string ParseForIpRegex(string textToSearch, string startBlock, string endBlock)
    {
        var pattern = $@"{startBlock}\D*\s*({IPV4_PATTERN}+).*{endBlock}";
        var ms = Regex.Match(textToSearch, pattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
        if(ms.Groups.Count > 0)
        {
            return ms.Groups[1].Value;
        }

        //For .Net Core apps
        //if (ms.Groups.TryGetValue("1", out var g))
        //{
        //    return g.Value;
        //}

        return string.Empty;
    }
4 голосов
/ 07 июня 2020

В дополнение к 2 ответам с решениями Regex, если адресная строка всегда идет после interace "system", то простое для l oop может выполнить работу.

interface "system"
    address 10.4.1.10/32       
    no shutdown
exit

Итак, мы go Просмотрите строки файла и проверьте, соответствует ли строка interace "system", затем возьмите следующее значение и проанализируйте его до строки IP-адреса.

public static string GetIpAddressFromFile(string fileName, string startLine)
{
    var lines = File.ReadAllLines(fileName);
    var ipAddress = string.Empty;

    for (var i = 0; i < lines.Length; i++)
    {
        var line = lines[i].Trim();

        if (line != startLine) continue;
        var addressLine = lines[i + 1].Trim().Replace("address", "");
        ipAddress = addressLine.Substring(0, addressLine.IndexOf("/", StringComparison.Ordinal));
        break;
    }

    return ipAddress.Trim();
}

Предположим, что ваш файл несовместим и адрес не стоит первым после interface "system"

interface "system"
    ...
    address 10.4.1.10/32       
    no shutdown
exit

Итак, в этом случае мы помещаем все строки между interface "system" и exit в список строк или словарь и получаем адресный ключ.

public static string GetIpAddressFromFile(string fileName, string startLine, string endLine)
{
    var lines = File.ReadAllLines(fileName);
    var ipAddress = string.Empty;
    var state = false;
    var results = new Dictionary<string, string>();

    foreach (var t in lines)
    {
        var line = t.Trim();
        if (line == startLine)
            state = true;

        if (line == endLine)
            state = false;

        if (!state) continue;
        var s = line.Split(" ");
        results.TryAdd(s[0], s[1]);
    }

    var result = results.GetValueOrDefault("address");
    if (result != null)
    {
        ipAddress = result.Substring(0, result.IndexOf("/", StringComparison.Ordinal));
    }

    return ipAddress;
}

Использование :

var startLine = "interface \"system\"";
var endLine = "exit";
var ip = GetIpAddressFromFile(@"File.txt", startLine);
//Or
var ip = GetIpAddressFromFile1(@"File.txt", startLine, endLine);

Оба метода проверены на вашем примере и возвращают:

10.4.1.10
3 голосов
/ 29 мая 2020

Если начало блока и конец блока четко определены, чтобы найти блок, вы можете просто:

  1. Найдите начало блока
  2. Сделайте что-нибудь со строками до конца блока

string line;
System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");

while((line = file.ReadLine()) != null && !line.Equals(START_OF_BLOCK)); // 1.

while((line = file.ReadLine()) != null && !line.Equals(END_OF_BLOCK)) // 2.
{
    // do something with the lines
}

file.Close();

Обновленный ответ после отредактированного вопроса:

Чтобы «извлечь» строку в виде IP-адреса внутри блока, вы можете, например, использовать Регулярные выражения с. NET Regex класс, с предварительным поиском нужного блока:

  1. Искать начало блока
  2. Искать внутри блока строку, содержащую "address"
  3. Извлеките IP-адрес из строки, используя Regexp.Match()

string line;
System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");
string pat = @"\b(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b";
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(pat);

while ((line = Console.ReadLine()) != null && !line.Equals(START_OF_BLOCK)); // 1.
while ((line = Console.ReadLine()) != null && !line.Equals(END_OF_BLOCK)) // 2.
{
    if (line.Contains("address"))
    {
        System.Text.RegularExpressions.Match ip = reg.Match(line);
        Console.WriteLine(ip);
        break; // break if you are sure there's only one ip in that block
    }
}

file.Close();
0 голосов
/ 12 июня 2020

Вот простой LINQ для этого:

var textData = File.ReadAllLines("Path goes here");
var address = string.Join("", textData
.SkipWhile(x => !x.Trim().StartsWith($"interface \"system\""))
.SkipWhile(x => !x.Trim().StartsWith($"address"))
.Take(1)).Split("address")[1].Trim();
  1. SkipWhile проходит через массив строк, пока не найдет строку, которая начинается как: "interface \" system \ "".
  2. Второй SkipWhile проходит часть после строки "interface \" system \ "", пока не найдет строку, которая начинается как "адрес".
  3. Затем вы берете (1) соответствующую строку и создаете из нее строку.
  4. Затем вы используете Split для создания нового массива, который содержит текст адреса и IP-адрес.
  5. После этого вы просто берете последнюю часть массива.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...