【问题标题】:Distinguishing string being parsed using String Split使用字符串拆分来区分正在解析的字符串
【发布时间】:2012-07-21 04:16:58
【问题描述】:

我需要解析格式如下的一行:

s = "Jun 21 09:47:50 ez-x5 user.debug if_comm: [TX] 02 30 20 0f 30 31 39 24 64 31 30 31 03 54 ";

我用 [TX] 或 [RX] 分割线路。这是我对解析后的字符串所做的:

s = "Jun 21 09:47:50 ez-x5 user.debug if_comm: [TX] 02 30 20 0f 30 31 39 24 64 31 30 31 03 54 ";
string[] stringSeparators = new string[] { "[TX] " + start_key };
string transfer = s.Split(stringSeparators, 2, StringSplitOptions.None)[1];
//At this point, transfer[] = 02 30 20 0f 30 31 39 24 64 31 30 31 03 54
if (!string.IsNullOrEmpty(transfer))
{
    string key = ""; 
    string[] split = transfer.Split(' ');
    if (split[0] == start_key)
    {
        for (int i = 0; i < key_length; i++)
        {
            key += split[i + Convert.ToInt32(key_index)];
        }
        TX_Handle(key);
    }
}

stringSeparators = new string[] { "[RX]" + start_key };
transfer = s.Split(stringSeparators, 2, StringSplitOptions.None)[1];
if (!string.IsNullOrEmpty(transfer))
{
    string key = "";
    string[] split = transfer.Split(' ');
    if (split[0] == start_key)
    {
        for (int i = 0; i < key_length; i++)
        {
            key += split[i + Convert.ToInt32(key_index)];
        }
        RX_Handle(key);
    }
}

基本上,因为我没有实际的方法来比较给定的标记是 [TX] 还是 [RX],我不得不使用上述方法来分隔字符串,这需要我编写两次基本相同的代码。

有什么方法可以解决这个问题并知道正在解析哪个令牌,这样我就不必复制我的代码?

【问题讨论】:

    标签: c# .net string parsing token


    【解决方案1】:

    执行此操作的最佳方法是查看常见的内容。你的代码有什么共同点?基于 2 个不同标记的拆分和基于 2 个不同标记的函数调用。这可以分解为条件,那么,为什么不将公共元素移动到条件中呢?

    const string receiveToken = "[RX] ";
    const string transmitToken = "[TX] ";
    
    string token = s.IndexOf(receiveToken) > -1 ? receiveToken  : transmitToken;
    

    ..现在你有你的令牌,所以你可以删除大部分重复。

    stringSeparators = new string[] { token + start_key };
    transfer = s.Split(stringSeparators, 2, StringSplitOptions.None)[1];
    if (!string.IsNullOrEmpty(transfer))
    {
        string key = "";
        string[] split = transfer.Split(' ');
        if (split[0] == start_key)
        {
            for (int i = 0; i < key_length; i++)
            {
                key += split[i + Convert.ToInt32(key_index)];
            }
            RX_TX_Handle(key, token);
        }
    }
    

    ..那么你可以有一个通用的处理程序,例如:

    void RX_TX_Handle(string key, string token)
    {
        token == receiveToken ? RX_Handle(key) : TX_Handle(key);
    }
    

    【讨论】:

    • 你的回答如此快速和专业,StackOverflow 拒绝我再接受 3 分钟的回答
    【解决方案2】:

    如何使用不同的方法并使用正则表达式。混入一点 LINQ,你就有了一些非常容易理解的代码。

    static void ParseLine(
        string line,
        int keyIndex,
        int keyLength,
        Action<List<byte>> txHandler,
        Action<List<byte>> rxHandler)
    {
        var re = new Regex(@"\[(TX|RX)\](?: ([0-9a-f]{2}))+");
        var match = re.Match(line);
        if (match.Success)
        {
            var mode = match.Groups[1].Value; // either TX or RX
            var values = match.Groups[2]
                .Captures.Cast<Capture>()
                .Skip(keyIndex)
                .Take(keyLength)
                .Select(c => Convert.ToByte(c.Value, 16))
                .ToList();
            if (mode == "TX") txHandler(values);
            else if (mode == "RX") rxHandler(values);
        }
    }
    

    或者不用正则表达式:

    static void ParseLine(
        string line,
        int keyIndex,
        int keyLength,
        Action<List<byte>> txHandler,
        Action<List<byte>> rxHandler)
    {
        var start = line.IndexOf('[');
        var end = line.IndexOf(']', start);
        var mode = line.Substring(start + 1, end - start - 1);
        var values = line.Substring(end + 1)
            .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
            .Skip(keyIndex)
            .Take(keyLength)
            .Select(s => Convert.ToByte(s, 16))
            .ToList();
        if (mode == "TX") txHandler(values);
        else if (mode == "RX") rxHandler(values);
    }
    

    【讨论】:

    • 嘿,这也是一个很好的答案。虽然我认为正则表达式对于这种简单性来说可能有点过头了,但仍然是一个很好的参考。
    • 这里不一定要用正则表达式,只需要识别出你感兴趣的token在[方括号]内即可。只需将那部分分开即可,然后从那里开始工作。正则表达式对此很有效,所以我选择了它。
    【解决方案3】:

    我不能 100% 确定这是否能回答您的问题,但我会创建一个负责解析令牌的 TokenParser 类。您会发现进行单元测试要容易得多。

    public enum TokenType
    {
        Unknown = 0,
        Tx = 1,
        Rx = 2
    }
    
    public class Token
    {
        public TokenType TokenType { get; set; }
        public IEnumerable<string> Values { get; set; }
    }
    
    public class TokenParser
    {
        public Token ParseToken(string input)
        {
            if (string.IsNullOrWhiteSpace(input)) throw new ArgumentNullException("input");
    
            var token = new Token { TokenType = TokenType.Unknown };
    
            input = input.ToUpperInvariant();
            if (input.Contains("[TX]"))
            {
                token.TokenType = TokenType.Tx;
            }
            if (input.Contains("[RX]"))
            {
                token.TokenType = TokenType.Rx;
            }
    
            input = input.Substring(input.LastIndexOf("]", System.StringComparison.Ordinal) + 1);
            token.Values = input.Trim().Split(Convert.ToChar(" "));
    
            return token;
        }
    }
    

    如果解析每个令牌的逻辑大不相同,则可以轻松扩展该示例以允许多个令牌解析器。

    【讨论】:

      猜你喜欢
      • 2012-12-25
      • 2012-04-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多