我正在嘗試使用boost::regex
從nm的demangled符號輸出中提取(完整)類名。 此示例程序從demangled符號中提取類
#include <vector>
namespace Ns1
{
namespace Ns2
{
template<typename T, class Cont>
class A
{
public:
A() {}
~A() {}
void foo(const Cont& c) {}
void bar(const A<T,Cont>& x) {}
private:
Cont cont;
};
}
}
int main()
{
Ns1::Ns2::A<int,std::vector<int> > a;
Ns1::Ns2::A<int,std::vector<int> > b;
std::vector<int> v;
a.foo(v);
a.bar(b);
}
將產生類中的下列符號A
Ns1::Ns2::A<int, std::vector<int, std::allocator<int> > >::A()
Ns1::Ns2::A<int, std::vector<int, std::allocator<int> > >::bar(Ns1::Ns2::A<int, std::vector<int, std::allocator<int> > > const&)
Ns1::Ns2::A<int, std::vector<int, std::allocator<int> > >::foo(std::vector<int, std::allocator<int> > const&)
Ns1::Ns2::A<int, std::vector<int, std::allocator<int> > >::~A()
我想優選使用單一的正則表達式模式來提取類(實例)名稱Ns1::Ns2::A<int, std::vector<int, std::allocator<int> > >
,但是我有問題解析<>
對中遞歸發生的類說明符。
有誰知道如何使用正則表達式模式(這是由boost::regex
支持)做到這一點?
我的解決方案(基於David Hammen的答案,因此接受):
我不使用(單)正則表達式來提取類和命名空間的符號。我已經創建了一個簡單的函數,剝掉從符號串的尾部包圍字符對(例如<>
或()
):
std::string stripBracketPair(char openingBracket,char closingBracket,const std::string& symbol, std::string& strippedPart)
{
std::string result = symbol;
if(!result.empty() &&
result[result.length() -1] == closingBracket)
{
size_t openPos = result.find_first_of(openingBracket);
if(openPos != std::string::npos)
{
strippedPart = result.substr(openPos);
result = result.substr(0,openPos);
}
}
return result;
}
這在從符號提取命名空間/類其他兩種方法中使用:
std::string extractNamespace(const std::string& symbol)
{
std::string ns;
std::string strippedPart;
std::string cls = extractClass(symbol);
if(!cls.empty())
{
cls = stripBracketPair('<','>',cls,strippedPart);
std::vector<std::string> classPathParts;
boost::split(classPathParts,cls,boost::is_any_of("::"),boost::token_compress_on);
ns = buildNamespaceFromSymbolPath(classPathParts);
}
else
{
// Assume this symbol is a namespace global function/variable
std::string globalSymbolName = stripBracketPair('(',')',symbol,strippedPart);
globalSymbolName = stripBracketPair('<','>',globalSymbolName,strippedPart);
std::vector<std::string> symbolPathParts;
boost::split(symbolPathParts,globalSymbolName,boost::is_any_of("::"),boost::token_compress_on);
ns = buildNamespaceFromSymbolPath(symbolPathParts);
std::vector<std::string> wsSplitted;
boost::split(wsSplitted,ns,boost::is_any_of(" \t"),boost::token_compress_on);
if(wsSplitted.size() > 1)
{
ns = wsSplitted[wsSplitted.size() - 1];
}
}
if(isClass(ns))
{
ns = "";
}
return ns;
}
std::string extractClass(const std::string& symbol)
{
std::string cls;
std::string strippedPart;
std::string fullSymbol = symbol;
boost::trim(fullSymbol);
fullSymbol = stripBracketPair('(',')',symbol,strippedPart);
fullSymbol = stripBracketPair('<','>',fullSymbol,strippedPart);
size_t pos = fullSymbol.find_last_of(':');
if(pos != std::string::npos)
{
--pos;
cls = fullSymbol.substr(0,pos);
std::string untemplatedClassName = stripBracketPair('<','>',cls,strippedPart);
if(untemplatedClassName.find('<') == std::string::npos &&
untemplatedClassName.find(' ') != std::string::npos)
{
cls = "";
}
}
if(!cls.empty() && !isClass(cls))
{
cls = "";
}
return cls;
}
的buildNamespaceFromSymbolPath()
方法簡單地串接有效命名空間部分:
std::string buildNamespaceFromSymbolPath(const std::vector<std::string>& symbolPathParts)
{
if(symbolPathParts.size() >= 2)
{
std::ostringstream oss;
bool firstItem = true;
for(unsigned int i = 0;i < symbolPathParts.size() - 1;++i)
{
if((symbolPathParts[i].find('<') != std::string::npos) ||
(symbolPathParts[i].find('(') != std::string::npos))
{
break;
}
if(!firstItem)
{
oss << "::";
}
else
{
firstItem = false;
}
oss << symbolPathParts[i];
}
return oss.str();
}
return "";
}
至少isClass()
方法使用正則表達式來掃描一個構造方法中的所有碼元(不幸似乎不爲類只含有成員函數工作):
std::set<std::string> allClasses;
bool isClass(const std::string& classSymbol)
{
std::set<std::string>::iterator foundClass = allClasses.find(classSymbol);
if(foundClass != allClasses.end())
{
return true;
}
std::string strippedPart;
std::string constructorName = stripBracketPair('<','>',classSymbol,strippedPart);
std::vector<std::string> constructorPathParts;
boost::split(constructorPathParts,constructorName,boost::is_any_of("::"),boost::token_compress_on);
if(constructorPathParts.size() > 1)
{
constructorName = constructorPathParts.back();
}
boost::replace_all(constructorName,"(","[\\(]");
boost::replace_all(constructorName,")","[\\)]");
boost::replace_all(constructorName,"*","[\\*]");
std::ostringstream constructorPattern;
std::string symbolPattern = classSymbol;
boost::replace_all(symbolPattern,"(","[\\(]");
boost::replace_all(symbolPattern,")","[\\)]");
boost::replace_all(symbolPattern,"*","[\\*]");
constructorPattern << "^" << symbolPattern << "::" << constructorName << "[\\(].+$";
boost::regex reConstructor(constructorPattern.str());
for(std::vector<NmRecord>::iterator it = allRecords.begin();
it != allRecords.end();
++it)
{
if(boost::regex_match(it->symbolName,reConstructor))
{
allClasses.insert(classSymbol);
return true;
}
}
return false;
}
如所提到的如果類沒有提供任何構造函數,則last方法不能安全地找到類名,並且在大的符號表上很慢。但至少這似乎涵蓋了你可以從nm的符號信息中得到什麼。
我已經離開regex這個問題的標籤,其他用戶可能會發現正則表達式不是正確的方法。
不'nm'配備了'--demangle'的選擇嗎?爲什麼要重新發起全面掛鉤? –
@KerrekSB我已經使用了demangled符號,我想從它們中提取類名。 –
哦,好的。但是,看起來模板語法沒有描述常規語言。這更像是XML([我們都知道這是怎麼回事]](http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454) )。 –