我不建议使用正则表达式“解析”SIP 标头。
正如在 cmets 中已经提到的,处理属性变得笨拙。此外,您会发现规范 (rfc 2616/rfc 822) 中有一些微妙的细节很难做到正确。
我之前使用 Boost Spirit 创建了一个 SIP 标头解析器:
我实际上已经直播创建了该解析器。如果您想看的话,这里是直播视频:part #1、part #2、part #3 和 part #4。
在这里使用解析器生成器的好处是您不会得到原始匹配组,而是可以直接解析成对进一步处理有用的东西,例如
using Headers = std::map<std::string, std::string>;
Live On Coliru
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <map>
using Headers = std::map<std::string, std::string>;
template <typename It> Headers parse_headers(It first, It last)
{
using namespace boost::spirit::qi;
auto& crlf = "\r\n";
auto& tspecials = " \t><@,;:\\\"/][?=}{:";
rule<It, std::string()> token, value;
token = +~char_(tspecials); // FIXME? should filter CTLs
value = *(char_ - (crlf >> &(~blank | eoi)));
BOOST_SPIRIT_DEBUG_NODES((token)(value));
//value = *(omit[ crlf >> !(~blank | eoi) ] >> attr(' ') | (char_ - crlf));
Headers headers;
bool ok = phrase_parse(first, last, (token >> ':' >> value) % crlf >> omit[*lit(crlf)], blank, headers);
#ifdef DEBUG
if (ok) std::cerr << "DEBUG: Parse success\n";
else std::cerr << "DEBUG: Parse failed\n";
if (first!=last) std::cerr << "DEBUG: Remaining unparsed input: '" << std::string(first,last) << "'\n";
#endif
if (ok && (first==last))
return headers;
throw std::runtime_error("Parse error in headers\n"); // TODO FIXME
}
int main()
{
boost::spirit::istream_iterator iter(std::cin >> std::noskipws), end;
for (auto& header : parse_headers(iter, end)) {
std::cout << "Key: '" << header.first << "', Value: '" << header.second << "'\n";
}
}
输入:
Via: SIP/2.0/UDP 10.10.1.99:5060;branch=z9hG4bK343bf628;rport
Contact: <sip:15@10.10.1.99>
Call-ID: 326371826c80e17e6cf6c29861eb2933@10.10.1.99
CSeq: 102 INVITE
User-Agent: Asterisk PBX
Max-Forwards: 70
Date: Wed, 06 Dec 2009 14:12:45 GMT
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY
Supported: replaces
Content-Type: application/sdp
Content-Length: 258
From: "Test 15" <sip:15@10.10.1.99>
; tag = fromtag
To: <sip:13@10.10.1.13>;tag=totag
打印输出
Key: 'Allow', Value: 'INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY'
Key: 'CSeq', Value: '102 INVITE'
Key: 'Call-ID', Value: '326371826c80e17e6cf6c29861eb2933@10.10.1.99'
Key: 'Contact', Value: '<sip:15@10.10.1.99>'
Key: 'Content-Length', Value: '258'
Key: 'Content-Type', Value: 'application/sdp'
Key: 'Date', Value: 'Wed, 06 Dec 2009 14:12:45 GMT'
Key: 'From', Value: '"Test 15" <sip:15@10.10.1.99>
; tag = fromtag'
Key: 'Max-Forwards', Value: '70'
Key: 'Supported', Value: 'replaces'
Key: 'To', Value: '<sip:13@10.10.1.13>;tag=totag'
Key: 'User-Agent', Value: 'Asterisk PBX'
Key: 'Via', Value: 'SIP/2.0/UDP 10.10.1.99:5060;branch=z9hG4bK343bf628;rport'