在c ++中解析文本标头包的问题

时间:2012-06-05 12:16:19

标签: c++ sip

我正在尝试解析SIP协议的标头包(类似于HTTP),这是一种基于文本的协议。 标题中的字段没有订单。 例如:如果有3个字段,f1,f2和f3,它们可以任意顺序出现f3,f2,f1,f1。

这增加了我的解析器的复杂性,因为我不知道哪个会先出现。

我应该怎样做才能克服这种复杂性?

2 个答案:

答案 0 :(得分:1)

最终,您只需将处理与收据顺序分离即可。要做到这一点,请在遇到字段时重复循环,并在循环内确定它是哪种字段类型,然后调度到该字段类型的处理。如果您可以立即处理这些字段,但是如果您需要保存为字段类型提供的潜在多个值,您可以(例如)将它们放入vector或甚至共享的multimap键入字段名称或ID。

的伪代码:

Field x;
while (x = get_next_field(input))
{
    switch (x.type())
    {
       case Type1: field1_values.push_back(x.value()); break;
       case Type2: field2 = x.value(); break;  // just keep the last value seen...
       default: throw std::runtime_error("unsupported field type");
    }
}

// use the field1_values / field2 etc. variables....

答案 1 :(得分:0)

Tony已经提出了主要想法,我会更具体。

解析的基本思想是它通常分为几个阶段。在你的情况下,你需要将lexing部分(提取标记)与语义部分(作用于它们)分开。

你可以用不同的方式进行,因为我更喜欢结构化方法,让我们假设我们有一个简单的结构表示头部:

struct SipHeader {
    int field1;
    std::string field2;
    std::vector<int> field3;
};

现在,我们创建一个函数,该函数接受字段名称及其值,并适当填充SipHeader结构的相应字段。

void parseField(std::string const& name, std::string const& value, SipHeader& sh) {
    if (name == "Field1") {
       sh.field1 = std::stoi(value);
       return;
    }

    if (name == "Field2") {
       sh.field2 = value;
       return;
    }

    if (name == "Field3") {
       // ...
       return;
    }

    throw std::runtime_error("Unknown field");
 }

然后迭代标题的行,每行分隔名称和值并调用此函数。

显然有改进:

  • 而不是if-chain,您可以使用仿函数地图,或者您可以完全标记化来源并将字段存储在std::map<std::string, std::string>
  • 您可以使用状态机技术立即对其进行操作而无需复制

但基本建议是一样的:

  

要管理复杂性,您需要在正交子任务中分离任务。