使用boost regex对文本进行标记

时间:2012-03-27 14:52:13

标签: c++ regex pcre boost-regex

我在母亲的生日那天忘记了正则表达式。这是一个主要的PITA。无论如何,我想要一个RE来解析HTTP响应状态行并正确捕获子元素。我得到了这个工作:

  const boost::regex status_line("HTTP/(\\d+?)\\.(\\d+?) (\\d+?) (.*)\r\n");
  std::string status_test1("HTTP/1.1 200 hassan ali\r\n");

  boost::smatch what;
  std::cout << regex_match(status_test1,what, status_line, boost::match_extra) << std::endl;
  std::cout << what.size() << std::endl;

  BOOST_FOREACH(std::string s, what)
  {
    std::cout << s << std::endl;
  }

第四个捕获组是我所讨论的,特别是对这些词进行说明。但我不需要它,所以我的工作已经完成。但是,我仍然想知道如何标记一个空格分隔的句子,该句子以'\ 0'结尾,这会产生一个被剥离的单词的向量/数组。

我无法使用以下片段

  const boost::regex sentence_re("(.+?)( (.+?))*");
  boost::smatch sentence_what;
  std::string sentence("hassan ali syed ");

  std::cout << boost::regex_match(sentence,sentence_what,sentence_re, boost::match_extra) << std::endl;

  BOOST_FOREACH(std::string s, sentence_what)
  {
    std::cout << s << std::endl;
  }

它不应与"hassan ali syed "匹配,但它应匹配"hassan ali syed",并且捕获组应输出hassan ali syed(带换行符),但它会输出hassan syed syed(请注意,第三个syed <space>syed中的空格。我认为捕获组无法处理递归实体?

那么,是否有一种干净的方法可以在PCRE语法中指定一个标记化任务,从而产生一个干净的标记向量(不重复 - 即,我不希望嵌套组尝试剥离空白)。

我知道这不是工作的正确工具,spirit / lexx或boost :: tokenise是最好的,我知道这不是正确的方法。在.net中进行屏幕抓取时,我会在文本体中找到令牌,重复将正则表达式应用到正文中,直到它用完了令牌。

2 个答案:

答案 0 :(得分:1)

这让我想起了一个类似的问题Capturing repeating subpatterns in Python regex

如果以空格分隔的单词的数量被限制为某些最大的令牌数,那么你可以直接使用一大堆额外的子模式,有点像:

"HTTP/(\\d+?)\\.(\\d+?) (\\d+?) ([^ ]+\s)?([^ ]+\s)?([^ ]+\s)?([^ ]+\s)?\n\r"

这当然是可怕的。

如果你想要一个嵌套组,我不会认为这可以在你的regexp实现中没有“重复子模式”支持的情况下完成(参见Python中使用的非标准regex模块链接的问题。)使用基本字符串函数 - 你当地的等价物string.split()几乎肯定会更好。

答案 1 :(得分:0)

Boost可能能够进行递归分组,但不确定。我倾向于它不能 我只知道.NET可以做到这一点。

您可以设计一个包含两个部分的正则表达式。第一部分捕获特定组,第二部分捕获在一个组中所有其余组。然后,您可以在捕获的第二部分上执行另一个递归正则表达式。

这样的事情:
(specific)(part)(to)(capture)(all the remaining text)

然后对前一个剩余的文本捕获执行一段时间(/(部分)/)正则表达式。

以下是你如何在升级中做到这一点 -

const string status = "HTTP/1.1 200 hassan ali\r\n";

boost::regex rx_sentence ( "HTTP/(\\d+)\\.(\\d+)\\s+(\\d+)\\s*([^\\s]+(?:\\s+[^\\s]+)*)?.*" );
boost::regex rx_token ( "[^\\s]+" );

if ( boost::regex_match( status, what, rx_sentence) )
{
    std::cout << "\nMatched:\n-----------------\n" << "'" << what[0] << "'" << std::endl;

    std::cout << "\nStatus (match groups):\n-----------------" << std::endl;
    for (int i=1; i < 4; i++)
    {
        std::cout << i << " = '" << what[i] << "'" << std::endl;
    }
    std::cout << "\nTokens (search of group 4):\n-----------------" << std::endl;
    const string token_str = what[4];

    std::string::const_iterator start = token_str.begin();
    std::string::const_iterator end   = token_str.end();

    while ( boost::regex_search(start, end, what, rx_token) )
    {
        string token(what[0].first, what[0].second);
        cout << "'" << token << "'" << endl;
        start = what[0].second;
    }
}
else
    std::cout << "Didn't match" << std::endl;