使用 boost::regex 解析包含枚举的 *.cpp 文件。

Parsing *.cpp file containing enum using boost::regex.

我已经解析文件并将内容拆分为枚举或枚举 类。

std::string sourceString = readFromFile(typesHDestination);
boost::smatch xResults;
std::string::const_iterator Start = sourceString.cbegin();
std::string::const_iterator End = sourceString.cend();

while (boost::regex_search(Start, End, xResults, boost::regex("(?<data_type>enum|enum\s+class)\s+(?<enum_name>\w+)\s*\{(?<content>[^\}]+?)\s*\}\s*")))
{
    std::cout << xResults["data_type"]
        << " " << xResults["enum_name"] << "\n{\n";

    std::string::const_iterator ContentStart = xResults["content"].begin();
    std::string::const_iterator ContentEnd = xResults["content"].end();
    boost::smatch xResultsInner;

    while (boost::regex_search(ContentStart, ContentEnd, xResultsInner, boost::regex("(?<name>\w+)(?:(?:\s*=\s*(?<value>[^\,\s]+)(?:(?:,)|(?:\s*)))|(?:(?:\s*)|(?:,)))")))
    {
        std::cout << xResultsInner["name"] << ": " << xResultsInner["value"] << std::endl;

        ContentStart = xResultsInner[0].second;
    }

    Start = xResults[0].second;
    std::cout << "}\n";
}

枚举没有注释也没关系。

我尝试添加命名组 <comment> 以在枚举中保存评论,但每次都失败了。 (\/{2}\s*.+) - 双斜杠注释示例。

我使用 online regex 和 boost::regex.

进行了测试
  1. 第一步——从*.cpp文件到<data_type> <enum_name> <content> 正则表达式:

(?'data_type'enum|enum\s+class)\s+(?'enum_name'\w+)\s*{\s*(?'content'[^}]+?)\s*}\s*

  1. <content><name> <value> <comment> 正则表达式:

(?'name'\w+)(?:(?:\s*=\s*(?'value'[^\,\s/]+)(?:(?:,)|(?:\s*)))|(?:(?:\s*)|(?:,)))

最后一个有错误。有什么方法可以修复它并添加功能以在群组中存储评论吗?

正如一些评论所说,用 正则表达式 解析源文件可能不是一个好主意,除了一些简单的情况

例如这个源文件,来自:http://en.cppreference.com/w/cpp/language/enum

#include <iostream>

// enum that takes 16 bits
enum smallenum: int16_t
{
    a,
    b,
    c
};


// color may be red (value 0), yellow (value 1), green (value 20), or blue (value 21)
enum color
{
    red,
    yellow,
    green = 20,
    blue
};

// altitude may be altitude::high or altitude::low
enum class altitude: char
{ 
     high='h',
     low='l', // C++11 allows the extra comma
}; 

// the constant d is 0, the constant e is 1, the constant f is 3
enum
{
    d,
    e,
    f = e + 2
};

//enumeration types (both scoped and unscoped) can have overloaded operators
std::ostream& operator<<(std::ostream& os, color c)
{
    switch(c)
    {
        case red   : os << "red";    break;
        case yellow: os << "yellow"; break;
        case green : os << "green";  break;
        case blue  : os << "blue";   break;
        default    : os.setstate(std::ios_base::failbit);
    }
    return os;
}

std::ostream& operator<<(std::ostream& os, altitude al)
{
    return os << static_cast<char>(al);
}

int main()
{
    color col = red;
    altitude a;
    a = altitude::low;

    std::cout << "col = " << col << '\n'
              << "a = "   << a   << '\n'
              << "f = "   << f   << '\n';
} 

这里的关键模式是:从enum开始到;结束,你无法预测enum和[之间的任何文本=15=] 会有很多的可能!为此,您可以使用 .*? lazy star

因此,如果我想提取所有 enums 我使用:

注意:这不是有效的方法

boost::regex rx( "^\s*(enum.*?;)" );

boost::match_results< std::string::const_iterator > mr; // or boost::smatch


std::ifstream ifs( "file.cpp" );
const uintmax_t file_size = ifs.seekg( 0, std::ios_base::end ).tellg();
                            ifs.seekg( 0, std::ios_base::beg );   // rewind

std::string whole_file( file_size, ' ' );
ifs.read( &*whole_file.begin(), file_size );
ifs.close();

while( boost::regex_search( whole_file, mr, rx ) ){
    std::cout << mr.str( 1 ) << '\n';
    whole_file = mr.suffix().str();
} 

输出将是:

enum smallenum: int16_t
{
    a,
    b,
    c
};
enum color
{
    red,
    yellow,
    green = 20,
    blue
};
enum class altitude: char
{
     high='h',
     low='l', // C++11 allows the extra comma
};
enum
{
    d,
    e,
    f = e + 2
};

当然,对于这种简单的事情,我更喜欢使用:

perl -lne '$/=unlef;print  while/^\s*(enum.*?;)/smg' file.cpp  

具有相同的输出。

如果您想分别匹配每个部分,此模式可能会对您有所帮助

^\s*(enum[^{]*)\s*({)\s*([^}]+)\s*(};)

But again this is not a good idea except for some simple source files. Since C++ Source Code has free style and not all code writers follow the standard rules. For example with the pattern above, I assumed that (};) the } comes with ; and if someone separates them ( which is still a valid code ) the pattern will be failed to match.

我同意使用正则表达式解析复杂数据并不是最佳解决方案这一事实。我省略了几个主要条件。首先,我解析了某种包含 emuns 和枚举 类 的生成源代码。所以代码中没有惊喜,而且代码是有规律的。所以我用正则表达式解析常规代码。

答案: (第一步是一样的,第二步是固定的) 如何使用正则表达式解析 enums/emun 类:

  1. 第一步-从*.cpp文件到<data_type> <enum_name> <content>正则表达式:

(?'data_type'enum|enum\s+class)\s+(?'enum_name'\w+)\s*{\s*(?'content'[^}]+?)\s*}\s*

  1. <content><name> <value> <comment> 正则表达式:

^\s*(?'name'\w+)(?:(?:\s*=\s*(?'value'[^,\n/]+))|(?:[^,\s/]))(?:(?:\s$)|(?:\s*,\s*$)|(?:[^/]/{2}\s(?'comment'.*$)))

所有测试都正常,这里用颜色标记了文本。