首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >字符串解析技术

字符串解析技术
EN

Stack Overflow用户
提问于 2017-01-25 11:09:03
回答 7查看 4.3K关注 0票数 2

我正试图找到一种将消息字符串解析为对象的好方法。字符串的长度是固定的,如下所述。

  • protocol = int(2)
  • 消息类型=字符串(1)
  • 测量=字符串(4)

做一个简单的String.Split是可行的,但是当您开始接近字符串的末尾时,我想可能会有些麻烦。例如:

代码语言:javascript
复制
var field1 = s.SubString(0,2);
var field2 = s.SubString(2,4);
....
var field99 = s.SubString(88,4); // difficult magic numbers

我考虑使用Regex,并认为这可能更令人困惑。

我试图想出一个优雅的解决方案,在这里我可以创建一个Parser,它被传递给一个'config‘,它将详细说明如何解析字符串。

就像..。

代码语言:javascript
复制
 MyConfig config = new MyConfig()
 config.Add("Protocol",    Length=2, typeof(int));
 config.Add("MessageType", Length=1, typeof(char));


 Parser p = new Parser(config);
 var parserResult = p.Parse(message);

...but,我一分钟就绕圈转,什么也没做。任何指点都会有很大帮助。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2017-01-25 11:29:53

我不认为如果这样做正确的话,判决是不会令人困惑的。您可以使用命名捕获组,并且可以非常整洁地定义它(例如,对于前三个字段,您可以任意扩展这些字段):

代码语言:javascript
复制
const string GRP_PROTOCOL = "protocol";
const string GRP_MESSAGE_TYPE = "msgtype";
const string GRP_MEASUREMENT = "measurement";

Regex parseRegex = new Regex(
    $"(?<{GRP_PROTOCOL}>.{{2}})" +
    $"(?<{GRP_MESSAGE_TYPE}>.{{1}})" +
    $"(?<{GRP_MEASUREMENT}>.{{4}})");

还可以在数组中定义组及其长度:

代码语言:javascript
复制
const string GRP_PROTOCOL = "protocol";
const string GRP_MESSAGE_TYPE = "msgtype";
const string GRP_MEASUREMENT = "measurement";

Tuple<string, int>[] groups = {
    Tuple.Create( GRP_PROTOCOL, 2 ),
    Tuple.Create( GRP_MESSAGE_TYPE, 1 ),
    Tuple.Create( GRP_MEASUREMENT, 4 )
};

Regex parseRegex =
    new Regex(String.Join("", groups.Select(grp => $"(?<{grp.Item1}>.{{{grp.Item2}}})").ToArray()));

然后,您可以在需要时按名称访问组:

代码语言:javascript
复制
Match match = parseRegex.Match(message);
string protocol = match.Groups[GRP_PROTOCOL].Value;
string msgType = match.Groups[GRP_MESSAGE_TYPE].Value;
string measurement = match.Groups[GRP_MEASUREMENT].Value;
票数 3
EN

Stack Overflow用户

发布于 2017-01-25 11:42:09

因此,一个简单的消息结构:

代码语言:javascript
复制
class Message
{
    public DateTime DateTime { get; set; }
    public int Protocol { get; set; }
    public string Measurement { get; set; }
    public string Type { get; set; }
    //....
}

与一个知道如何反序列化它的类组合在一起:

代码语言:javascript
复制
class MessageSerializer
{
    public Message Deserialize(string str)
    {
        Message message = new Message();
        int index = 0;
        message.Protocol = DeserializeProperty(str, ref index, 2, Convert.ToInt32);
        message.Type = DeserializeProperty(str, ref index, 1, Convert.ToString);
        message.Measurement = DeserializeProperty(str, ref index, 4, Convert.ToString);
        message.DateTime = DeserializeProperty<DateTime>(str, ref index, 16, (s) =>
        {
            // Parse date time from 2013120310:28:55 format
            return DateTime.ParseExact(s, "yyyyMMddhh:mm:ss", CultureInfo.CurrentCulture);
        });
        //...
        return message;
    }

    static T DeserializeProperty<T>(string str, ref int index, int count, 
        Func<string, T> converter)
    {
        T property = converter(str.Substring(index, count));
        index += count;
        return property;
    }
}
票数 4
EN

Stack Overflow用户

发布于 2017-01-25 11:49:15

如果输入字符串中的属性是固定宽度的,那么Regex在实现和性能方面都是开销。创建一个通用解析器的想法是好的,但是如果您有多个解析器要实现的话,它是有意义的。因此,如果只有一个特定的实现,就没有理由有抽象。

我会和StringReader一起去

代码语言:javascript
复制
using (var reader = new StringReader(input)) {
}

然后,...and创建一些助手扩展方法,如下所示:

代码语言:javascript
复制
// just a sample code, to get the idea

public static string ReadString(this TextReader reader, int count)
{
    var buffer = new char[count];
    reader.Read(buffer, 0, count);
    return string.Join(string.Empty, buffer);
}

public static int ReadNumeric(this TextReader reader, int count)
{
    var str = reader.ReadString(count);
    int result;
    if (int.TryParse(str, out result))
    {
        return result;
    }
    // handle error
}

// ...

最后的用法是这样的:

代码语言:javascript
复制
using (var reader = new StringReader(input)) {
    var protocol = reader.ReadNumeric(2);
    var messageType = reader.ReadString(1);
    var measurement = reader.ReadString(4);
    // ...
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41850029

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档