将C/C++程序放到网络上并不是简单的复制粘贴,大部分网站和blog是不提供代码的直接粘贴的(当然优快云是不错的),之前在sina写博客的时候就碰到类似的问题。
C/C++抓换为HTML的关键是处理注释,关键字。当然也可以对字符串,数字进行一定的加亮处理。
1.我以前用C++写过一个程序,其实表面上是C++,只是输出用了cout和cin而已,其他的函数和思想还是C语言的。当时实现的代码加亮的结果是这样的。
- 这个程序的思想在main函数中体现到了,即一行一行的读取和处理文件直到文件尾。
- 首先是changeType()函数,这个函数主要的目的是处理掉HTML中的敏感字符,让代码能够以HTML格式来显示。举个例子来说"<"和">"这样的字符时不能直接在HTML中显示的,因为这样的字符同时也是HTML种的关键符号。HTML解决显示问题的办法是用"<"和">"来替换他们,这个函数大致就是做这样的事情。
- 然后是ChangeColor()函数主要是处理对于注释和关键字的加亮。注意注释是首要的,在注释中的关键字是不需要加亮的。找出C语言中的段注释和行注释并添加THML代码中的颜色代码,这里使用了很多string函数,比如比较和插入,我自己也对其中的函数做了一些小扩展,如CmpStr来更好的适应这个程序。最后是检索每一个关键字并且加亮。这里的思想是仅仅检查C语言中的特定标志来做出判断,这样做是有问题的,请看实际代码仔细想一下。
name:C/C++程序生成网页
author:不是苹果
date:08-12-20
**********************************************************************/
#include <fstream>
#include <iostream>
#include <string.h>
using namespace std;
//关键字数组
char KEYWORD[55][15] = {"auto","bool","break","case","catch","char","class","const","continue","default","delete","do","double","else","enum","explicit","extern","false","float","for","friend","goto","if","inline","int","long","mutable","namespace",
"new","operator","private","protected","public","register","return","short","signed","sizeof","static","struct","switch","template","this","true","try",
"typedef","typeid","typename","union","unsigned","using","virtual","void","volatile","while"};
//函数名:CmpStr,比较两个字符串
//参数:strS,待比较的数组指针.strK,用来比较的数组指针,这里是关键字
//返回值:若待比较的数组后的几个字母和关键字的一样则返回真
//描述:只是用后面的来测试前面的看一部分是否相等,不同是strcmp
bool CmpStr( char *strS, char *strK)
{
int i;
if (strlen(strS) >= strlen(strK))
{
for (i=0; i<strlen(strK); i++)
{
if (*(strS+i) != *(strK+i))
{
return false;
}
}
return true;
}
else
{
return false;
}
}
//函数名:ForKey,由判断字符串之前来决定此字符串是否是从指针除开始的
//参数:str,字符串指针。len,字符串长度
//返回值:如果符合条件返回真
bool ForKey( char *str, int len)
{
if (strlen(str) < len)
{
if ( (*(str-1) != ';') && (*(str-1) != '/x28') && (*(str-1) != '*') )
{
return false;
}
return true;
}
return true;
}
//函数名:ChangeType,改变文本形式
//参数:某字符串的指针
//返回值:无
void ChangeType( char *str)
{
int sCounter; //原数组元素指示
int dCounter = 0; //转换数组的元素指示
char strCopy[700] = {'/0'}; //
for (sCounter=0; sCounter<strlen(str); sCounter++)
{
switch(str[sCounter])
{
case ' ':
strcpy(&strCopy[dCounter]," ");
dCounter += 6;
break;
case '<':
strcpy(&strCopy[dCounter],"<");
dCounter += 4;
break;
case '>':
strcpy(&strCopy[dCounter],">");
dCounter += 4;
break;
case '"':
strcpy(&strCopy[dCounter],""");
dCounter += 6;
break;
case '&':
strcpy(&strCopy[dCounter],"&");
dCounter += 5;
break;
case '/':
strcpy(&strCopy[dCounter],"/");
dCounter += 5;
break;
default:
strCopy[dCounter] = str[sCounter];
dCounter +=1;
break;
}
}
strcpy(&str[0], &strCopy[0]);
}
//函数名:ChangeColor,改变文本的颜色
//参数:字符串的指针
//返回值:无
void ChangeColor( char *str)
{
int sCounter;
int sCounter2;
int dCounter = 0;
int keywordC;
static bool fNotes = false;
char strCopy[700] = {'/0'};
for (sCounter=0; sCounter<strlen(str); sCounter++)
{
if (CmpStr(&str[sCounter], "/*"))
{
fNotes = true;
strcpy(&strCopy[dCounter], "<span style=/"color:#008000;/">");
dCounter += 29;
strncpy(&strCopy[dCounter], &str[sCounter], strlen(&str[0])-sCounter);
dCounter += strlen(&str[0])-sCounter;
strcpy(&strCopy[dCounter], "</span>");
sCounter = sCounter + strlen(&str[0])-sCounter-1;
dCounter += 7;
goto FF1;
}
for (sCounter2=0; sCounter2<strlen(&str[0]); sCounter2++)
{
if (CmpStr(&str[sCounter2], "*/"))
{
fNotes = false;
strcpy(&strCopy[dCounter], "<span style=/"color:#008000;/">");
dCounter += 29;
strncpy(&strCopy[dCounter], &str[sCounter], strlen(&str[0]));
dCounter += strlen(&str[0]);
strcpy(&strCopy[dCounter], "</span>");
sCounter = sCounter + strlen(&str[0])-1;
dCounter += 7;
goto FF1;
}
}
if (fNotes == true)
{
strcpy(&strCopy[dCounter], "<span style=/"color:#008000;/">");
dCounter += 29;
strncpy(&strCopy[dCounter], &str[sCounter], strlen(&str[0]));
dCounter += strlen(&str[0]);
strcpy(&strCopy[dCounter], "</span>");
sCounter = sCounter + strlen(&str[0])-1;
dCounter += 7;
goto FF1;
}
if (CmpStr(&str[sCounter], "//"))
{
strcpy(&strCopy[dCounter], "<span style=/"color:#008000;/">");
dCounter += 29;
strncpy(&strCopy[dCounter], &str[sCounter], strlen(&str[0])-sCounter);
dCounter += strlen(&str[0])-sCounter;
strcpy(&strCopy[dCounter], "</span>");
sCounter = sCounter + strlen(&str[0])-sCounter-1;
dCounter += 7;
goto FF1;
}
for (keywordC=0; keywordC<55; keywordC++)
{
if ( CmpStr(&str[sCounter], KEYWORD[keywordC]) && ( CmpStr(&str[sCounter+strlen(KEYWORD[keywordC])], " ") || str[sCounter+strlen(KEYWORD[keywordC])] == '(' || str[sCounter+strlen(KEYWORD[keywordC])] == '/0' || str[sCounter+strlen(KEYWORD[keywordC])] == '*' ) && ForKey(&str[sCounter], strlen(&str[0])) )
{
strcpy(&strCopy[dCounter], "<span style=/"color:#0000ff;/">");
dCounter += 29;
strncpy(&strCopy[dCounter], &str[sCounter], strlen(KEYWORD[keywordC]));
dCounter += strlen(KEYWORD[keywordC]);
strcpy(&strCopy[dCounter], "</span>");
sCounter = sCounter + strlen(KEYWORD[keywordC]) - 1;
dCounter += 7;
goto FF1;
}
}
strCopy[dCounter] = str[sCounter];
dCounter +=1;
FF1: ;
}
strcpy(&str[0], &strCopy[0]);
}
//主函数
int main()
{
ifstream fin("1.txt");
ofstream fout("2.html");
fout << "<div style=/"font:14px/16px Consolas,Fixedsys,Arial;/">" << endl;
while (!fin.eof())
{
char sentence[700] = {'/0'};
fin.getline(&sentence[0], 700);
ChangeType(sentence);
ChangeColor(sentence);
fout << &sentence[0] << "<br />";
}
fout << "</div>";
fout.close();
return 0;
}
2.这个是最近用C++写的程序。主要是想真正用C++来写一下这个程序,并且对之前的程序的思绪混乱和BUG做一些修正。
- 现在对于整个处理程序用类进行了封装,放在类class C2html中。两个public函数,一个是OpenFile函数打开文件 ,另外一个就是Transform函数进行处理。两个函数的具体的处理的分部函数放在private中。
- OpenFile函数包括三个函数。1.打开关键字文件,可能注意到了,在上面的程序中是将key文件放在程序中的数组中的,这样不便于输入,同时也不便于灵活管理。如果需要处理java代码的加亮的话只需要更改key文件,同时对程序做出一些改变就可以了,而不需要在程序中重新输入数组。2.初始化额外的关键字文件,说白了就是上面提到的"<"和">"等HTML敏感字节。没有放入像key一样放入文件储存室因为比较少同时也是固定的。3.打开需要转换的源文件。这里与上面的程序不同的是一次将整个文件读入一个string向量中,一次进行处理,避免反复读取和写入文件。上面的三个函数都可以加入打开文件的异常处理。
- Transform函数包含五个函数。1.处理代码中的敏感字节,这个和上面程序中的ChangeType功能是类似的。2.处理注释,和上面的ChangeColor前一部分功能是类似的,但是更加严谨。3.4.分别是处理代码中的字符串和关键字的,和ChangeColor的后一部分功能是类似的,但是更加严谨。对于注释和关键字的判断不仅是单纯的代码中的标志,也有HTML中已有的标志来判断,这样更加准确。具体请看代码部分。5.保存源文件为转换之后的文件。
- 前面表示代码行比现实出来的代码短时因为浏览器会自动换行,解决的办法是自己写程序的时候长句尽量换行。
这个是工程文件的下载地址 http://hi.youkuaiyun.com/link.php?url=http://yufei34514.download.youkuaiyun.com
包括C2html.h文件,C2html.cpp文件,main.cpp文件
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#ifndef _C2HTML_H_
#define _C2HTML_H_
#include <string>
#include <vector>
#include <map>
#include <set>
#include <fstream>
#include <iostream>
using std::vector;
using std::string;
using std::map;
using std::set;
class C2html
{
public:
void OpenFile( char* fileName)
{
OpenKeyFile(); //打开并处理关键字文件
InitExtraKey(); //加载html中需要处理的特定字符
OpenSourceFile(fileName); //打开源文件加入vector<string>
}
void Transform()
{
ReplaceExtraKey(); //替换网页中需要处理的特定字符
ColorComment(); //对注释文本进行加亮
ColorString(); //对字符串进行加亮
ColorKey(); //对关键字进行加亮
SaveFile(); //保存文件
}
private:
void OpenKeyFile();
void InitExtraKey();
void OpenSourceFile( char* fileName);
void ReplaceExtraKey();
void ColorComment();
void ColorString();
void ColorKey();
void SaveFile();
vector<string> key; //关键字
vector<string> source; //源文件
map<string, string> extraKey; //对于html中特定需要替换的关键字
//set<int> commentLine; //源文件中为注释的行的集合
int fileLine; //源文件总行数
};
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#include "C2html.h"
using namespace std;
//打开关键字文件,并且将文件读入
//到keyWord这个string向量组中
void C2html::OpenKeyFile()
{
ifstream fileKey( "key.dat");
string keyWord;
while (fileKey >> keyWord)
key.push_back(keyWord);
fileKey.close();
}
void C2html::InitExtraKey()
{
//将HTML代码中的某些敏感字符先转化
//放入extraKey这个pair对象中
extraKey.insert(make_pair( " ", " "));
extraKey.insert(make_pair( "/t", " "));
extraKey.insert(make_pair( "<", "<"));
extraKey.insert(make_pair( ">", ">"));
}
//打开源文件并且读入source这个string向量组中
void C2html::OpenSourceFile( char* fileName)
{
ifstream fin(fileName);
string line;
while (getline(fin, line))
source.push_back(line);
fin.close();
fileLine = static_cast< int>(source.size());
}
void C2html::ReplaceExtraKey()
{
for (vector<string>::iterator sourceLine = source.begin(); sourceLine != source.end(); ++sourceLine)
{
for (map<string, string>::iterator singleExtraKey= extraKey.begin();
singleExtraKey != extraKey.end(); ++singleExtraKey)
{
string::size_type keyWordPos = 0;
//查找和替换而外的字符,这些字符保存阻碍singleExtraKey中,在InitExtraKey函数中初始化
while ((keyWordPos = (*sourceLine).find(singleExtraKey->first, keyWordPos)) != string::npos)
{
(*sourceLine).replace(keyWordPos, (singleExtraKey->first).size(), singleExtraKey->second);
//keyWordPos要更新以便用于下一次的查找
//因为string已经改变了
keyWordPos += (singleExtraKey->second).size();
}
}
}
}
void C2html::ColorComment()
{
//块注释的标志
pair<string, string> commentBlock( "/*", "*/");
//行注释的标志
string commentInLine( "//");
//用来替换块注释的字符串
pair<string, string> commentReplace( "<span style=/"color:#008000/">", "</span>");
bool isCommentBlockOver = true;
for (vector<string>::iterator sourceLine = source.begin(); sourceLine != source.end(); ++sourceLine)
{
string::size_type keyWordPos = 0;
string::size_type bPos = 0; //块注释的位置
string::size_type lPos = 0; //行注释的位置
string::size_type qPos = 0; //引号的位置
//一行中可能有多个块注释,所以
//循环查找直到再也找不到关键字为止才退出
while ( true)
{
if (isCommentBlockOver) //寻找新的块注释
{
//分别找出行注释,块注释,引号,然后根据他们的位置做出判断
bPos = (*sourceLine).find(commentBlock.first, keyWordPos);
lPos = (*sourceLine).find(commentInLine, keyWordPos);
qPos = (*sourceLine).find(string( "/""), keyWordPos);
//引号在前面,后面的内容是字符串,跳出,等到专门处理
//字符串的函数来处理
if ((qPos < lPos) && (qPos < bPos) && (qPos != string::npos))
{
keyWordPos = qPos + string( "/"").size();
while ((keyWordPos = (*sourceLine).find(string( "/""), keyWordPos)) != string::npos)
{
if ((*sourceLine)[ static_cast<string::size_type>(keyWordPos - 1)] != '//')
{
keyWordPos += string( "/"").size();
break;
}
else keyWordPos += string( "/"").size();
}
continue;
}
//行注释在前面
else if ((lPos > bPos) && (bPos != string::npos))
{
keyWordPos = bPos;
isCommentBlockOver = false;
(*sourceLine).replace(keyWordPos, (commentBlock.first).size(), commentReplace.first + commentBlock.first);
keyWordPos = keyWordPos + (commentBlock.first + commentReplace.first).size();
}
//块注释在前面
else if ((lPos < bPos) && (lPos != string::npos))
{
keyWordPos = lPos;
(*sourceLine).replace(keyWordPos, commentInLine.size(), commentReplace.first + commentInLine);
(*sourceLine).append(commentReplace.second);
break;
}
//都没有的话,跳出
else break;
}
if (!isCommentBlockOver) //如果已经有块注释的开始标志,寻找块注释的关闭标志
{
//找到关闭标志
if ((keyWordPos = (*sourceLine).find(commentBlock.second, keyWordPos)) != string::npos)
{
isCommentBlockOver = true;
(*sourceLine).replace(keyWordPos, (commentBlock.second).size(), commentBlock.second + commentReplace.second);
keyWordPos = keyWordPos + (commentBlock.second + commentReplace.second).size();
}
//暂时没找到
else
{
//commentLine.insert(lineNum);
(*sourceLine).insert(0, commentReplace.first);
(*sourceLine).append(commentReplace.second);
break; //此行没找到块关闭标志,跳出到下一行继续找
}
}
}
}
}
void C2html::ColorString()
{
string stringKey( "/"");
pair<string, string> stringReplace( "<span style=/"color:#a31515;/">", "</span>");
for (vector<string>::iterator sourceLine = source.begin(); sourceLine != source.end(); ++sourceLine)
{
string::size_type posStart = 0; //处理的开始位置
string::size_type posEnd = 0; //处理的结束位置
string::size_type posI = 0; //临时变量
bool hasComment = true;
while ( true)
{
//确定末尾界限"<"
//如果找到,说明必定是ColorComment处理过的
if ((posI = (*sourceLine).find( "<", posStart)) != string::npos)
{
posEnd = posI;
}
else
{
hasComment = false;
posEnd = static_cast<string::size_type>((*sourceLine).size());
}
//在界限内查找替换所有
string::size_type posTemp = posStart; //现在所在的位置
bool isStringOver = true;
while ( true)
{
if (isStringOver)
{
//在区间限制内找开始标志
if (((posTemp = (*sourceLine).find(stringKey, posTemp)) != string::npos) && (posTemp < posEnd))
{
isStringOver = false;
(*sourceLine).replace(posTemp, stringKey.size(), stringReplace.first + stringKey);
posTemp = posTemp + (stringKey + stringReplace.first).size();
posEnd = posEnd + (stringKey + stringReplace.first).size();
}
else break; //在界限内没找到,跳出此层,等待下一个界限
}
if (!isStringOver)
{
//找配对的结束标记(请保证程序的正确性,不然出错)
while (((posTemp = (*sourceLine).find(stringKey, posTemp)) != string::npos) && (posTemp < posEnd))
{
//如果找到了并且前面一个不是转义符的话就加亮,否则继续找
if ((*sourceLine)[ static_cast<string::size_type>(posTemp - 1)] != '//')
{
isStringOver = true;
(*sourceLine).replace(posTemp, stringKey.size(), stringKey + stringReplace.second);
posTemp = posTemp + (stringKey + stringReplace.second).size();
posEnd = posEnd + (stringKey + stringReplace.second).size();
break;
}
else posTemp += stringKey.size();
}
}
}
//判断前面是否找到了"<",如果找到了说明还有
//结束的标记</span>,就继续找html的标记
if (hasComment)
{
posStart = (*sourceLine).find( "</span>", posStart);
posStart += static_cast<string::size_type>( string( "</span>").size() );
}
else break; //已经没有comment了
}
}
}
void C2html::ColorKey()
{
string preStr( "<span style=/"color:#0000ff;/">");
string endStr( "</span>");
//查找关键字并改变颜色
int lineNum = 0; //行号
for (vector<string>::iterator sourceLine = source.begin();
sourceLine != source.end(); ++sourceLine, ++lineNum)
{
string::size_type posStart = 0;
string::size_type posEnd = 0;
string::size_type posI = 0;
bool hasComment = true;
//找完整行
while ( true)
{
//寻找"<"
if ((posI = (*sourceLine).find( "<", posStart)) != string::npos)
{
posEnd = posI;
}
else
{
hasComment = false;
posEnd = static_cast<string::size_type>((*sourceLine).size());
}
//在界限内查找替换所有
for (vector<string>::iterator singleKey= key.begin(); singleKey != key.end(); ++singleKey)
{
string::size_type keyWordPos = posStart;
while (((keyWordPos = (*sourceLine).find(*singleKey, keyWordPos)) != string::npos)
&& (keyWordPos < posEnd))
{
//判断关键字的两侧,如果不是字母数字下划线就认为是关键字
//替换extraKey并不替换字母数字下划线,对这里没有影响
if (keyWordPos != 0)
{
if (isalnum((*sourceLine)[keyWordPos - 1]) || (*sourceLine)[keyWordPos - 1] == '_')
{
keyWordPos += (*singleKey).size();
continue;
}
}
if (isalnum((*sourceLine)[keyWordPos + (*singleKey).size()])
|| (*sourceLine)[keyWordPos + (*singleKey).size()] == '_')
{
keyWordPos += (*singleKey).size();
continue;
}
//判断完成,是关键字
(*sourceLine).replace(keyWordPos, (*singleKey).size(),
preStr + *singleKey + endStr);
keyWordPos += (preStr + *singleKey + endStr).size();
posEnd += (preStr + *singleKey + endStr).size();
}
}
if (hasComment)
{
posStart = (*sourceLine).find( "</span>", posStart);
posStart += static_cast<string::size_type>( string( "</span>").size() );
}
else break; //已经没有comment了
}
}
}
void C2html::SaveFile()
{
ofstream fout( "out.htm");
//保存文件,以下是为了实现显示行号
fout << "<div style=/"padding:0;font-family:consolas,/"幼圆/",monospace;font-size:10px;/">";
fout << "<div style=/"padding:0;margin:0;float:left;color:#808080;"
<< "border-right:1px solid #808080;background-color:#e0e0e0;/">";
for ( int i = 0; i != fileLine; i++)
{
fout << " " << (i + 1) << " <br />";
}
fout << "</div>";
fout << "<div style=/"padding:0;float:left;padding-left:3px;/">";
for (vector<string>::iterator dLine = source.begin(); dLine != source.end(); ++dLine)
{
fout << *dLine << "<br />";
}
fout << "</div>";
fout << "<div style=/"clear:both;font-size:0px;line-height:0px;/"> </div>";
fout << "</div>";
fout << "<div style=/"clear:left;/"> </div>";
fout.close();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <fstream>
#include "C2html.h"
using namespace std;
int main()
{
C2html cppFile;
cppFile.OpenFile( "change.txt");
cppFile.Transform();
return 0;
}