Выберите два символа из строки в LINQ - PullRequest
0 голосов
/ 12 декабря 2018

Мне нужно преобразовать шестнадцатеричную строку, начинающуюся с 0x или шестнадцатеричную строку, преобразованную с BitConverter в массив byte.Для этого я использую эту функцию, которая работает очень хорошо:

public static byte[] ConvertToByteArray(this string s)
{
    if (s.StartsWith("0x"))
    {
        var ret = new byte[(s.Length - 2) / 2];
        for (int i = 2; i < s.Length; i += 2)
        {
            ret[(i - 2) / 2] = Convert.ToByte(string.Concat(s[i], s[i + 1]), 16);
        }
        return ret;
    }
    else
        return s.Split('-').Select(b => Convert.ToByte(b, 16)).ToArray();
}

пример ввода, исходящий из своего рода сетевого устройства (воспринимайте это как сообщение, зарегистрированное с помощью wireshark):

byte[] data1 = "0x020206000000022800A601585E40".ConvertToByteArray();
byte[] data2 = "02-02-06-00-00-00-02-28-00-A6-01-58-5E-40".ConvertToByteArray();
CollectionAssert.AreEqual(data1, data2);

Теперь я хотел бы понять, как написать первую возможность (начинается с 0x) в LINQ, чтобы избавиться от этого 1990-го цикла for.

Есть ли способ выбрать два символа одновременно или есть более элегантный способ, чем мой?

Ответы [ 3 ]

0 голосов
/ 12 декабря 2018

Обновление:

После прочтения комментария ОП я вижу, что он хочет иметь возможность использовать шестнадцатеричные строки произвольной длины.Я хотел бы использовать функцию итератора, чтобы вернуть ваши шестнадцатеричные пары, чтобы соответствовать результату вашего разделения.Затем вы можете передать любое из перечисляемых значений через одно и то же преобразование, например, так:

public byte[] ConvertToByteArray(string s)
{
    IEnumerable<string> query = Enumerable.Empty<string>();

    if (s.StartsWith("0x"))
    {
        query = IterateHexPairs(s.Substring(2));
    }
    else
    {
        query = s.Split('-');
    }

    return query.Select(b => Convert.ToByte(b, 16)).ToArray();

    IEnumerable<string> IterateHexPairs(string hexLiteral)
    {
        char? previousNibble = null;

        foreach (var nibble in hexLiteral)
        {
            if (previousNibble != null)
            {
                yield return new string(new char[] { previousNibble.Value, nibble });
                previousNibble = null;
            }
            else
            {
                previousNibble = nibble;   
            }                               
        }
    }
}

Это позволяет избежать дублирования логики преобразования, поскольку оба они получают от IEnumerable.Единственная разница - источник IEnumerable.Измените код, который дает вам перечислимый, как вы считаете нужным.Я думал, что функция Iterator будет более удобной в обслуживании, но вы можете выполнить запрос Linq для достижения того же результата, например:

public byte[] ConvertToByteArray(string s)
{
    IEnumerable<string> query = Enumerable.Empty<string>();

    if (s.StartsWith("0x"))
    {        
        // omit the 0x
        query = s.Skip(2)
        // get the char and index, so we can pair them up
                 .Select((c, i) => new { Char = c, Index = i })
        // group them into pairs
                 .GroupBy(o => o.Index / 2)
        // select them as new strings, so they can be converted
                 .Select(g => new string(g.Select(o => o.Char).ToArray()));
    }
    else
    {
        query = s.Split('-');
    }

    return query.Select(b => Convert.ToByte(b, 16)).ToArray();
}
0 голосов
/ 12 декабря 2018

Это эквивалент вашего цикла linq, независимо от других соображений:

if (s.StartsWith("0x"))
{
    return
    s.Skip(2)
     .Select((x,i) => new {index = i, value = x})
     .GroupBy(pair => pair.index / 2)
     .Select(grp => string.Join("", grp.Select(x=>x.value)))
     .Select(x => Convert.ToByte(x,16))
     .ToArray();
}

Но, похоже, это решение вашей проблемы отсутствия кода 90ish:

public static byte[] ConvertToByteArray(this string s)
{
    string tmp = s.Replace("0x","").Replace("-","");
    tmp = Regex.Replace(tmp, ".{2}", "$0-");
    return tmp.Split('-').Select(b => Convert.ToByte(b, 16)).ToArray();
}
0 голосов
/ 12 декабря 2018

Ну, я думаю, сначала вы можете взглянуть на это

Используя пример ввода @jdweng.

string input = "0x0123456789ABCDE".Replace("0x", string.Empty);
long intValue = long.Parse(s, System.Globalization.NumberStyles.HexNumber);

Теперь, если вы долго, вы можете легко преобразовать его в байт [].

byte[] array = BitConverter.GetBytes(intValue);

Я знаю, что это не решение LINQ для вашей проблемы, а чисто и просто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...