从LINQ的字符串中选择两个字符

时间:2018-12-12 11:59:54

标签: c# arrays string linq

我必须将以def pad(s): for k, v in dictionary.items(): s = s.replace(k, v) return s >>> dictionary = { "(": " ( ", ")": " ) "} >>> pad("if (x < 0) {") 'if ( x < 0 ) {' 开头的十六进制字符串或以0x转换为十六进制的字符串转换为BitConverter数组。为此,我使用此功能,效果很好:

byte

示例输入,来自某种网络设备(将其视为用wirehark记录的消息):

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

现在,我想了解如何在LINQ中编写第一种可能性(以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); 开头),以摆脱1990年代的for循环。

是否可以同时选择两个字符,还是比我更优雅的方法?

3 个答案:

答案 0 :(得分:1)

好吧,我想首先可以看看这个

使用@jdweng示例输入。

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

现在,如果您很长,可以轻松将其转换为byte []。

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

我知道这不是LINQ解决您的问题的方法,但是它很干净而且很简单。

答案 1 :(得分:1)

更新:

阅读OP的评论后,我看到他希望能够使用任意长度的十六进制字符串。我很想使用迭代器函数返回您的十六进制对,以匹配拆分结果。然后,您可以通过相同的转换来提供任何可枚举的数据,例如:

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查询进行bodge以达到相同的结果,如下所示:

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

答案 2 :(得分:1)

这是循环的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();
}