0

Делаю запрос на сервер, результатом является byte[] (массив байтов обозвал как data). Не знаю на сколько разумно, но для начала конвертирую в string

string result = System.Text.Encoding.UTF8.GetString(data);

И так, есть уже строка такого типа <par1="value1" par2="value2"...> К примеру, мне нужно получить значение параметра par7. Какой оптимальный вариант для этого есть? Оптимальный - самый быстрый

  • 1
    Оптимальный по скорости, или по к-ву кода? Регулярка - не оптимальный способ. Строковые IndexOf и Substring - отработают само оптимально. А дальше зависит от того, насколько универсальным должно быть решение, т.к. некоторые сайты могут позволить себе такое: par='value' par="a='b' par=value – nick_n_a May 30 '19 at 09:27
  • Вариант ещё оптимальнее - искать < как байт, найти нужные символы через Array.IndexOf<byte> и Array.ConstrainedCopy и брать GetString - нужные куски, не преобразовуя в строку даже названий ключей (конвертировать только значения), это ускорит разбор. Но кода будет много. Да... Substring - не самая оптимальная ф-ция... имеется ввиду что она оптимальнее Regex. – nick_n_a May 30 '19 at 09:41
  • оптимальный по скорости. Но, конечно, огромный метод неприятен для глаз ) – Александр Пузанов May 30 '19 at 09:44
  • @АлександрПузанов а он и не будет очень огромным. Просто регулярка будет в 1-3 строки – Andrei Khotko May 30 '19 at 09:56
  • @AndreiKhotko - регулярка - будет всегда коротко медленно и неоптимально - зато кода немного. Ручной парсинг заточеный под опрелеленные особенности того что ищется - будет быстрее, при этом работа непосредственно с байтами будет быстрее чем работа с строками - но и число строк кода будет больше соответственно. Чем быстрее - тем больше кода, как правило. Третий вариант - попробовать несколько библиотек - и выбрать оптимальную по-скорости.Список либ тут https://ru.stackoverflow.com/questions/420354/%d0%9a%d0%b0%d0%ba-%d1%80%d0%b0%d1%81%d0%bf%d0%b0%d1%80%d1%81%d0%b8%d1%82%d1%8c-html-%d0%b2-net – nick_n_a May 30 '19 at 09:59
  • @nick_n_a а я и не спорил с этим. Я просто сказал, что регулярка короче, поэтому метод будет казаться огромным по сравнению с регулярным выражением – Andrei Khotko May 30 '19 at 10:00
  • веб- сервер мне вернет строго в таком формате <name="Poops and Moops" count="1000" ...> – Александр Пузанов May 30 '19 at 10:03
  • @ nick_n_a Честно, я не понял смысл реализации. Я приведу полный пример <Name="Default" Count="5" Copies="7" ID="566 565 7676"....> – Александр Пузанов May 30 '19 at 10:07
  • мне нужно получить значение по ключу – Александр Пузанов May 30 '19 at 10:07
  • @АлександрПузанов сейчас напишу свой вариант через обычный метод – Andrei Khotko May 30 '19 at 10:26
  • @АлександрПузанов а значение value может содержать внутри себя кавычки? – Andrei Khotko May 30 '19 at 10:28
  • Оно на самом деле выглядит так: <Name="..." ...>? Или всё же это xml и в начале есть имя элемента: <elem attr="..." ...>? – Alexander Petrov May 30 '19 at 10:28
  • да, верно, это xml по своей структуре – Александр Пузанов May 30 '19 at 20:20
  • Значение value ковычек внутри себя содержать не может в моем случае – Александр Пузанов May 30 '19 at 20:31
  • это xml - тогда возьмите любой xml-парсер. Проще всего работать с XElement – Alexander Petrov May 31 '19 at 09:32
  • 1
    Дополню. От сервера вы получаете поток (stream) данных, так? Если там действительно xml, то читаем из этого потока (без лишнего преобразования в строку) прямо в XElement/XDocument. И дальше удобно работаем с ним. Если приведёте больше данных, то можно будет дать рабочий пример кода. – Alexander Petrov May 31 '19 at 12:41
  • Да, так и есть, от сервера я получаю поток данных. На сервере это xml в чистом виде. Все что у меня естьдля клиента - это метод, который возвращает поток байт. Если возможно прямо в XML, а потом обращаться к аттрибутам, то мне так, конечно удобнее – Александр Пузанов May 31 '19 at 22:31
  • Ниже привели код. Да он рабочий. Но вот с xML попробую, т.к. более понятнее и проще для меня ваш вариант. Буду пробовать – Александр Пузанов May 31 '19 at 22:35

1 Answers1

1

Мое решение такое:

private static void Main(string[] args)
{
    var input = @"<par1=""value1"" par2=""value2"" par7=""value7"">";
    var parameter = "par2";

    var val = GetValue(input, parameter);

    Console.WriteLine($"{parameter} = {val}");
    Console.ReadKey();
}

/// <summary>
/// Get value of param from specific string  
/// </summary>
/// <param name="input">Specific string</param>
/// <param name="sample">param name</param>
/// <returns>Value represented by string. if not found - string.Empty</returns>
private static string GetValue(string input, string sample)
{
    var isInQuotes = false; // Для определения того, находится ли текущий символ внутри кавычек

    for (int i = 0; i <= input.Length - sample.Length - 3; i++) 
    {
        if (input[i] == '"')
            isInQuotes = !isInQuotes;

        if (IsSame(input, i, sample) && !isInQuotes)
        {
            var j = i + sample.Length;

            // Идем до открывающейся кавычки
            while (input[j] != '"')
            {
                j++;
                if (j == input.Length)
                    return string.Empty;
            }

            j++;

            var sb = new StringBuilder();

            // Идем до закрытия кавычек, при этом записывая значение в stringBuilder
            while (input[j] != '"')
            {
                sb.Append(input[j++]);
                if (j == input.Length)
                    return string.Empty;
            }

            return sb.ToString();
        }
    }

    return string.Empty;
}

/// <summary>
/// Check equality of sample and src substring
/// </summary>
/// <param name="src"></param>
/// <param name="from">Start index of src</param>
/// <param name="sample"></param>
/// <returns></returns>
private static bool IsSame(string src, int from, string sample)
{
    if (from + sample.Length > src.Length)
        return false;

    for (int i = 0; i < sample.Length; i++)
    {
        if (src[from + i] != sample[i])
            return false;
    }

    return true;
}

Тестирование и ревью этого куска кода приветствуется. Я не вставлял сюда проверку входной строки на открытие/закрытие тега <>.

В остальном все проверки есть (если я ничего не упустил).