根据代码行从文本文件中获取函数名称
Get function name from text file base on line of code
我有一个名为 'MyCpp.cpp' 的 C++ 源代码,它位于:C:\MyCpp.cpp
...
5 string CplusplusWarningFunction()
6 {
7 int a = 69;
8 int b = a + 1;
9 a = b;
10 b = 69;
11 return "42 is the answer";
12 }
...
现在我想写一个像这样的 C# 函数
void CodeAnalyzer()
{
string path = @"C:\MyCpp.cpp";
int line = 11;
IEnumerable<string> loc = File.ReadLines(path);
string code = loc.ElementAt(line-1);//Yes, it is 'return "42 is the answer";', good job!
string functionFullName = "???";//This suppose to be the string 'CplusplusWarningFunction()', but How to do it???
MessageBox.Show(string.Format("The code {0} at line {1} is in function {2}",code,line,functionFullName));
}
如何获取函数名来替换字符串“???”在上面的 C# 代码中?
我知道这是可以做到的,因为 MS 的 FxCop 可以做到(FxCop 分析编译后的目标代码,而不是原始源代码)。好吧,如果编译后的目标代码可以完成,为什么不使用原始源代码。
而Visual Studio可以像下图这样,希望有办法访问Visual Studio API:
感谢阅读。
鉴于只有一个功能,每一行你都可以尝试
//do this in a foreach loop that will iterate through every line
string functionName;
if (line.Split(' ').Where(x => x.Contains("()") && !x.Contains(".")).Count() > 0)
{
functionName = line.Split(' ').Where(x => x.Contains("()") && !x.Contains(".")).First();
}
现在这将适用于您的示例代码,但这也是非常 初级的,我相信在很多情况下这都行不通。不过,这可能不是一个糟糕的起点。
我想出了这样的代码,到目前为止还不错。
class CppFunction
{
public string FunctionName { get; set; }
public int StartLine { get; set; }
public int EndLines { get; set; }
}
List<CppFunction> AnalyzeCpp(string path)
{
List<CppFunction> lstCppFunc = new List<CppFunction>();
IEnumerable<string> loc = File.ReadLines(path, encode);
string[] locNoCom = RemoveComment(loc);
RemoveIfdefineDebug(locNoCom);
int level = 0;
CppFunction crtFunc = null;
int lineCount = 0;
StringBuilder builder = new StringBuilder();
bool startName = false;
string builderToString;
string lastLine = "";
foreach (string line in locNoCom)
{
lineCount++;
if (string.IsNullOrWhiteSpace(line))
{
lastLine = line;
continue;
}
if (level <= 0)
{
if (line.Contains('('))
{
crtFunc = new CppFunction();
if (line.Trim().IndexOf('(') == 0)
builder.Append(lastLine);
builder.AppendLine(line);
crtFunc.StartLine = lineCount;
startName = true;
}
if (startName)
{
builderToString = builder.ToString();
if (line != builderToString.Replace("\r\n",string.Empty))
builder.AppendLine(line);
if (line.Contains(')'))
{
startName = false;
if (crtFunc != null)
crtFunc.FunctionName = builder.ToString();
builder.Clear();
}
}
}
if(line.Contains('{'))
{
foreach(char c in line)
{
if (c == '{')
level++;
}
}
if(line.Contains('}'))
{
foreach (char c in line)
{
if (c == '}')
level--;
}
if (crtFunc != null && level <= 0)
{
crtFunc.EndLines = lineCount;
lstCppFunc.Add(crtFunc);
crtFunc = null;
level = 0;
}
}
lastLine = line;
}
return lstCppFunc;
}
现在我们有了函数列表及其起始行、结束行,当我们得到代码行时,我们可以检查它是否在哪个函数之间,BAM - 我们得到了函数行。
编辑:
我们还需要删除评论以增加正义度
string[] RemoveComment(IEnumerable<string> loc)
{
string[] line = loc.ToArray();
bool startComment = false;
int startComPos=0;
int endComPos=-1;
int count = line.Length;
string comment;
bool mistakeComment;
int multiCommentStart, multiCommentEnd;
for(int i=0;i<count;i++)
{
if (string.IsNullOrWhiteSpace(line[i]))
continue;
if (line[i].Contains("//"))
{
mistakeComment = false;
if(line[i].Contains("*//*"))//Case mistake /**//**/ with //
{
if ((line[i].IndexOf("//") - line[i].IndexOf("*//*")) == 1)
{
mistakeComment = true;
}
}
if(!mistakeComment)
{
comment = line[i].Substring(line[i].IndexOf("//"));
line[i] = line[i].Replace(comment, string.Empty);
}
}
if(line[i].Contains("/*"))
{
startComment = true;
startComPos = line[i].IndexOf("/*");
endComPos = -1;
}
else
{
startComPos = 0;
}
if (startComment)
{
if(!string.IsNullOrEmpty(line[i]))
{
if (line[i].Contains("*/"))
{
startComment = false;
endComPos = line[i].IndexOf("*/", startComPos);
}
else
endComPos = -1;
if (endComPos == -1)
{
comment = line[i].Substring(startComPos);
line[i] = line[i].Replace(comment, string.Empty);
}
else
{
comment = line[i].Substring(startComPos, endComPos - startComPos + 2);
line[i] = line[i].Replace(comment, string.Empty);
}
}
}
if (line[i].Contains("/*"))
while((multiCommentStart = line[i].IndexOf("/*")) >= 0 &&
(multiCommentEnd = line[i].IndexOf("*/")) >= 0 &&
multiCommentEnd > multiCommentStart)
{
comment = line[i].Substring(multiCommentStart, multiCommentEnd - multiCommentStart + 2);
line[i] = line[i].Replace(comment, string.Empty);
}
}
return line;
}
哦,我们还需要删除调试代码
void RemoveIfdefineDebug(string[] linesCode)
{
bool startRemove = false;
for(int i=0;i<linesCode.Length;i++)
{
if(startRemove)
{
if (linesCode[i].Contains("#endif"))
{
startRemove = false;
}
else
linesCode[i] = string.Empty;
}
if (linesCode[i].Contains("#ifdef "))
{
startRemove = true;
}
}
}
最后是主函数
string GetCodeAndFunctionName(string path, int line)
{
List<CppFunction> lstCppFunc = AnalyzeCpp(path);
foreach(CppFunction func in lstCppFunc)
{
if(func.EndLines >= line && func.StartLine <= line)
{
return func.FunctionName;
}
}
return "x";
}
我有一个名为 'MyCpp.cpp' 的 C++ 源代码,它位于:C:\MyCpp.cpp
...
5 string CplusplusWarningFunction()
6 {
7 int a = 69;
8 int b = a + 1;
9 a = b;
10 b = 69;
11 return "42 is the answer";
12 }
...
现在我想写一个像这样的 C# 函数
void CodeAnalyzer()
{
string path = @"C:\MyCpp.cpp";
int line = 11;
IEnumerable<string> loc = File.ReadLines(path);
string code = loc.ElementAt(line-1);//Yes, it is 'return "42 is the answer";', good job!
string functionFullName = "???";//This suppose to be the string 'CplusplusWarningFunction()', but How to do it???
MessageBox.Show(string.Format("The code {0} at line {1} is in function {2}",code,line,functionFullName));
}
如何获取函数名来替换字符串“???”在上面的 C# 代码中?
我知道这是可以做到的,因为 MS 的 FxCop 可以做到(FxCop 分析编译后的目标代码,而不是原始源代码)。好吧,如果编译后的目标代码可以完成,为什么不使用原始源代码。
而Visual Studio可以像下图这样,希望有办法访问Visual Studio API:
感谢阅读。
鉴于只有一个功能,每一行你都可以尝试
//do this in a foreach loop that will iterate through every line
string functionName;
if (line.Split(' ').Where(x => x.Contains("()") && !x.Contains(".")).Count() > 0)
{
functionName = line.Split(' ').Where(x => x.Contains("()") && !x.Contains(".")).First();
}
现在这将适用于您的示例代码,但这也是非常 初级的,我相信在很多情况下这都行不通。不过,这可能不是一个糟糕的起点。
我想出了这样的代码,到目前为止还不错。
class CppFunction
{
public string FunctionName { get; set; }
public int StartLine { get; set; }
public int EndLines { get; set; }
}
List<CppFunction> AnalyzeCpp(string path)
{
List<CppFunction> lstCppFunc = new List<CppFunction>();
IEnumerable<string> loc = File.ReadLines(path, encode);
string[] locNoCom = RemoveComment(loc);
RemoveIfdefineDebug(locNoCom);
int level = 0;
CppFunction crtFunc = null;
int lineCount = 0;
StringBuilder builder = new StringBuilder();
bool startName = false;
string builderToString;
string lastLine = "";
foreach (string line in locNoCom)
{
lineCount++;
if (string.IsNullOrWhiteSpace(line))
{
lastLine = line;
continue;
}
if (level <= 0)
{
if (line.Contains('('))
{
crtFunc = new CppFunction();
if (line.Trim().IndexOf('(') == 0)
builder.Append(lastLine);
builder.AppendLine(line);
crtFunc.StartLine = lineCount;
startName = true;
}
if (startName)
{
builderToString = builder.ToString();
if (line != builderToString.Replace("\r\n",string.Empty))
builder.AppendLine(line);
if (line.Contains(')'))
{
startName = false;
if (crtFunc != null)
crtFunc.FunctionName = builder.ToString();
builder.Clear();
}
}
}
if(line.Contains('{'))
{
foreach(char c in line)
{
if (c == '{')
level++;
}
}
if(line.Contains('}'))
{
foreach (char c in line)
{
if (c == '}')
level--;
}
if (crtFunc != null && level <= 0)
{
crtFunc.EndLines = lineCount;
lstCppFunc.Add(crtFunc);
crtFunc = null;
level = 0;
}
}
lastLine = line;
}
return lstCppFunc;
}
现在我们有了函数列表及其起始行、结束行,当我们得到代码行时,我们可以检查它是否在哪个函数之间,BAM - 我们得到了函数行。
编辑: 我们还需要删除评论以增加正义度
string[] RemoveComment(IEnumerable<string> loc)
{
string[] line = loc.ToArray();
bool startComment = false;
int startComPos=0;
int endComPos=-1;
int count = line.Length;
string comment;
bool mistakeComment;
int multiCommentStart, multiCommentEnd;
for(int i=0;i<count;i++)
{
if (string.IsNullOrWhiteSpace(line[i]))
continue;
if (line[i].Contains("//"))
{
mistakeComment = false;
if(line[i].Contains("*//*"))//Case mistake /**//**/ with //
{
if ((line[i].IndexOf("//") - line[i].IndexOf("*//*")) == 1)
{
mistakeComment = true;
}
}
if(!mistakeComment)
{
comment = line[i].Substring(line[i].IndexOf("//"));
line[i] = line[i].Replace(comment, string.Empty);
}
}
if(line[i].Contains("/*"))
{
startComment = true;
startComPos = line[i].IndexOf("/*");
endComPos = -1;
}
else
{
startComPos = 0;
}
if (startComment)
{
if(!string.IsNullOrEmpty(line[i]))
{
if (line[i].Contains("*/"))
{
startComment = false;
endComPos = line[i].IndexOf("*/", startComPos);
}
else
endComPos = -1;
if (endComPos == -1)
{
comment = line[i].Substring(startComPos);
line[i] = line[i].Replace(comment, string.Empty);
}
else
{
comment = line[i].Substring(startComPos, endComPos - startComPos + 2);
line[i] = line[i].Replace(comment, string.Empty);
}
}
}
if (line[i].Contains("/*"))
while((multiCommentStart = line[i].IndexOf("/*")) >= 0 &&
(multiCommentEnd = line[i].IndexOf("*/")) >= 0 &&
multiCommentEnd > multiCommentStart)
{
comment = line[i].Substring(multiCommentStart, multiCommentEnd - multiCommentStart + 2);
line[i] = line[i].Replace(comment, string.Empty);
}
}
return line;
}
哦,我们还需要删除调试代码
void RemoveIfdefineDebug(string[] linesCode)
{
bool startRemove = false;
for(int i=0;i<linesCode.Length;i++)
{
if(startRemove)
{
if (linesCode[i].Contains("#endif"))
{
startRemove = false;
}
else
linesCode[i] = string.Empty;
}
if (linesCode[i].Contains("#ifdef "))
{
startRemove = true;
}
}
}
最后是主函数
string GetCodeAndFunctionName(string path, int line)
{
List<CppFunction> lstCppFunc = AnalyzeCpp(path);
foreach(CppFunction func in lstCppFunc)
{
if(func.EndLines >= line && func.StartLine <= line)
{
return func.FunctionName;
}
}
return "x";
}