不过VB.NET确实有许多VB6没有的新功能,代码的自动排版就是一项,这也正是我们今天要实现的功能——VB代码格式化。 
先看下实现的效果: 
格式化前: 
 
For i = 0 To WebBrowser1.Document.All.length - 1 
If WebBrowser1.Document.All(i).tagName = "HTML" Then 
strContent = strContent & WebBrowser1.Document.All(i).innerHTML 
Exit For 
End If 
Next 
 格式化后: 
 
For i = 0 To WebBrowser1.Document.All.length - 1 
If WebBrowser1.Document.All(i).tagName = "HTML" Then 
strContent = strContent & WebBrowser1.Document.All(i).innerHTML 
Exit For 
End If 
Next 
 C++水平一直很烂,所以选择了C++作为练手语言写了这个简陋的VB代码格式化工具。代码不长,才200多行,标准C++实现。另外,为了彻底打消某些人继续使用VC6的念头,使用了auto关键字嘿嘿。好吧,废话少说,直接上代码: 
 
#include<iostream> 
#include<string> 
#include<vector> 
#include<algorithm> 
#include<fstream> 
using namespace std; 
//判断是否为空格 
bool isSpace(const char chr) 
{ 
return chr == ' '; 
} 
//去除左侧空白 
void leftTrim(string &str) 
{ 
string::iterator p=find_if(str.begin(),str.end(),not1(ptr_fun(isSpace))); 
str.erase(str.begin(),p); 
} 
//去除右侧空白 
void rightTrim(string& str) 
{ 
string::reverse_iterator p=find_if(str.rbegin(),str.rend(),not1(ptr_fun(isSpace))); 
str.erase(p.base(),str.end()); 
} 
//去除两侧空白 
string trim(const string& str) 
{ 
string strRet(str); 
leftTrim(strRet); 
rightTrim(strRet); 
return strRet; 
} 
//转换成小写 
string toLower(const string& str) 
{ 
string strRet(str); 
transform(strRet.begin(),strRet.end(),strRet.begin(),(int (*)(int))tolower); 
return strRet; 
} 
//判断是否以给定关键字开头 
bool startWith(const vector<string>& vecCodeKeywords,const string& strCodeLine) 
{ 
string line(toLower(strCodeLine)); 
for(auto keyword=vecCodeKeywords.begin(); keyword!=vecCodeKeywords.end(); keyword++) 
if(line.find(*keyword + " ")==0 || line== *keyword) 
return true; 
return false; 
} 
//IF...Then...特殊检查 
bool checkForIfThen(const string& strCodeLine) 
{ 
vector<string> vecIf; 
vecIf.push_back("if"); 
if(!startWith(vecIf,strCodeLine)) 
return false; 
if(toLower(strCodeLine).find("then")==string::npos) 
return false; 
string line(trim(toLower(strCodeLine))); 
if(line.length()<7) 
return false; 
return !(line.substr(line.length()-4,4) == "then"); 
} 
//格式化给定行并标记相关信息 
int formatAndMarkLine(string& strCodeLine) 
{ 
//起始关键字 "if","for","[Private | Friend | Public] [Static] [Sub | Function | Property | Type]","with","do","select" 
vector<string> vecStartKeywords; 
vecStartKeywords.push_back("if"); 
vecStartKeywords.push_back("for"); 
vecStartKeywords.push_back("with"); 
vecStartKeywords.push_back("do"); 
vecStartKeywords.push_back("select"); 
string _pfp[] = {"private","friend","public"}; //可空 
string _s[] = {"static"}; //可空 
string _sfpt[] = {"sub","function","property","type"}; 
//_pfp _s 都为空 
for(auto i=0; i<4; i++) 
vecStartKeywords.push_back(_sfpt[i]); 
//_pfp 为空 
for(auto i=0; i<4; i++) 
vecStartKeywords.push_back(_s[0] + " " + _sfpt[i]); 
//_s 为空 
for(auto i=0; i<4; i++) 
for(auto j=0; j<3; j++) 
vecStartKeywords.push_back(_pfp[j] + " " + _sfpt[i]); 
//_pfp _s 都不为空 
for(auto i=0; i<4; i++) 
for(auto j=0; j<3; j++) 
vecStartKeywords.push_back(_pfp[j] + " " + _s[0] + " " + _sfpt[i]); 
//终止关键字 "end if","next","End [Sub | Function | Property | Type]","end with","loop","end select" 
vector<string> vecEndKeywords; 
vecEndKeywords.push_back("end if"); 
vecEndKeywords.push_back("next"); 
vecEndKeywords.push_back("end with"); 
vecEndKeywords.push_back("loop"); 
vecEndKeywords.push_back("end select"); 
for(auto i=0; i<4; i++) 
vecEndKeywords.push_back("end " + _sfpt[i]); 
//中间关键字 "else","elseif","case" 
vector<string> vecMiddleKeywords; 
vecMiddleKeywords.push_back("else"); 
vecMiddleKeywords.push_back("elseif"); 
vecMiddleKeywords.push_back("case"); 
auto mark = 0; 
char c; 
auto n=0; 
string line; 
auto quote = false; //双引号状态 
/* 
规则: 
双引号内单引号不考虑,否则后面内容成为注释 
*/ 
auto space = true; //空白符状态 false 表示未遇到任何空白符 
while((c=strCodeLine[n++])) 
{ 
switch(c) 
{ 
case ' ': 
case '\t': 
if(quote) 
{ 
line += c; 
} 
else 
{ 
if(!space) 
{ 
line += c; 
space = true; 
} 
} 
break; 
case '"': 
space = false; 
quote = !quote; 
line += c; 
break; 
case '\'': 
space = false; 
if(quote) 
line += c; 
else 
{ 
line += " '"; //MsgBox("itianda") '单引号前有一个空格 
while((c=strCodeLine[n++])) //直接附加单引号后面内容 
line += c; 
continue; 
} 
break; 
case '_': //续行符 
space = false; 
line += c; 
if(!quote && n==(int)strCodeLine.length() && n-2>=0 && strCodeLine[n-2]==' ') 
mark |= 0x80; //10000000 
break; 
default: 
space = false; 
line += c; 
} 
} 
strCodeLine = line; 
if(startWith(vecStartKeywords,line) && !checkForIfThen(line)) 
mark += 1; 
if(startWith(vecEndKeywords,line)) 
mark += 2; 
if(startWith(vecMiddleKeywords,line)) 
mark += 3; 
return mark; 
} 
//将代码按行分割 
void splitToLines(const string& strCode, vector<string>& vecCodeLines) 
{ 
vecCodeLines.clear(); 
char c; 
auto n=0; 
string line; 
while((c=strCode[n++])) 
{ 
if(c!='\n') 
line += c; 
else 
{ 
vecCodeLines.push_back(line); 
line.clear(); 
} 
} 
if(line.length()) //最后一行为空则舍去 
vecCodeLines.push_back(line); 
} 
//格式化给定代码 
void formatCode(string& strCode,const string& strIndentString) 
{ 
vector<string> vecLines; //所有代码行 
splitToLines(strCode,vecLines); //获取所有代码行 
if(vecLines.size()==0) 
{ 
return; 
} 
auto indentLevel = 0; //缩进级别 
auto incompleteLine = false; //是否是未结束行 
for(auto line=vecLines.begin(); line!=vecLines.end(); line++) 
{ 
auto indent = indentLevel; 
auto mask = formatAndMarkLine(*line); 
switch(mask & ~0x80) 
{ 
case 0: 
break; 
case 1: 
indentLevel++; 
break; 
case 2: 
indent--; 
indentLevel--; 
break; 
case 3: 
indent--; 
break; 
} 
if(incompleteLine) 
indent++; 
incompleteLine = mask & 0x80; 
if(indent<0) 
indent = 0; 
if(indentLevel<0) 
indentLevel = 0; 
string strIndent; 
for(auto i=0; i<indent; i++) 
strIndent += strIndentString; 
*line = strIndent + *line; 
} 
strCode.clear(); 
for(auto line=vecLines.begin(); line!=vecLines.end(); line++) 
strCode+= trim(*line).length() ? "\n" + *line : ""; 
} 
int main() 
{ 
string indentString = " "; 
string code; 
ifstream inputFile("in.txt"); 
string line; 
while(getline(inputFile,line)) 
{ 
code += line + "\n"; 
} 
formatCode(code,indentString); 
ofstream outputFile("out.txt"); 
outputFile<<"Your beautiful code:"<<endl<< 
"-------------------------------------------------------------------" 
<<endl<<code<<endl<<endl<< 
"-------------------------------------------------------------------" 
<<endl<< 
" Formatted by itianda's PUVBFormatter" 
<<endl<< 
" http://www.programup.com/blog" 
<<endl; 
return 0; 
} 
 看过代码应该知道这是多么基本的实现了吧,好多细节都没有去仔细处理,比如没有考虑冒号连接多行的情况,所以如果你希望使用此工具,请不要把多行语句写到一行哦! 
最后提供一个我编译好的EXE下载:
PUVBFormatter 更新: 
增加select case…end select关键字,感谢jjww2999网友的反馈。 
本文来自: itianda's blog