Mail to Keith Dan
keith的天空
海阔凭鱼跃,天高任鸟飞

本来这个功能应该算是编辑器的一个附属功能,本来有一个JS的代码着色器(syntaxhighlighter),现在版本是1.51,但是由于其功能始终是客户端的,有一些服务器操作比较麻烦,于是自己写了一个,当前只是实现了C#版本。
在这里,我讲述一下该代码实现模式,这里主要讲讲循环和分组的机制

主体:

HighLightCode:为高亮代码的基类,并抽象,含有抽象方法
通过方法实现实例

public static HighLightCode CreateHighLightCode(CodeType regexcodetype)
        
{
            HighLightCode code 
= null;
            
if (regexcodetype == CodeType.CSharp)
            
{
                code 
= new RegexCSharp();
            }


            
return code;
        }


RegexCSharp:实现HighLightCode方法。
当前为C#实现了该方法,如果Java类实现该方法,则可以扩展出Java的着色代码.

思路:
如果我们直接使用正则表达式进行匹配,那么比较麻烦,会出现一些问题,如://string abc = "hello";那么"hello"会被分析为引号部分,而非注释部分。要解决该问题,我们先分析一下代码着色的原理和基础。
特殊的符号包括单引号,双引号,单行注释,多行注释的判断,由于这些情况都是成对的出现,我们需要找出这4个情况前后匹配的数据进行分组处理。
注意,单行注释由//开头,\r\n结尾
如:string abc= "hello!";
那么string abc=作为group1,"hello!"作为group2,;作为group3。那么在group1和group3我们需要的仅仅是对关键字进行匹配,在这里最简单的方法就是正则表达式进行匹配和着色。那么对于group2无非就是添加深红色而已。但是对于分组我们需要找到最先出现的符号位置,如:string abc = "hello // world!";此时的//应该作为字符串而非注释,所以它必须为group2中。

分组方法:
我们先讨论只有一个目标符号的情况。即:string abc= "hello!";
我们首先将4个符号的出现的初始位置找到,进行排序,得到位置最小的符号,那么该组就是以该符号为基准。在这里,我使用了List进行排序。得到位置最小的符号组,那么它就是我们要寻找的目标符号,于是寻找他的结尾符号,则可以得到它具体的字符串。

List<RegexItem> regexs = new List<RegexItem>();
            RegexItem regx 
= null;

            
int count = 0;
            
int pos1 = code.IndexOf('"', start);
            
if (pos1 > -1)
            
{
                count
++;
                regx 
= new RegexItem();
                regx.Postion 
= pos1;
                regx.RegexMode 
= Mode.DoubleQuotedString;
                regexs.Add(regx);
            }

            
int pos2 = code.IndexOf(BeginSingleLineComments, start);
            
if (pos2 > -1)
            
{
                count
++;
                regx 
= new RegexItem();
                regx.Postion 
= pos2;
                regx.RegexMode 
= Mode.SingleLineComments;
                regexs.Add(regx);
            }

            
int pos3 = code.IndexOf(BeginMultiLineComments, start);
            
if (pos3 > -1)
            
{
                count
++;
                regx 
= new RegexItem();
                regx.Postion 
= pos3;
                regx.RegexMode 
= Mode.MultiLineComments;
                regexs.Add(regx);
            }

            
int pos4 = code.IndexOf("'", start);
            
if (pos4 > -1)
            
{
                count
++;
                regx 
= new RegexItem();
                regx.Postion 
= pos4;
                regx.RegexMode 
= Mode.SingleQuotedString;
                regexs.Add(regx);
            }

如上:pos1,pos2,pos3,pos4分别得到4个符号的最初位置,并放置于一个List<RegexItem>中,count表示查找到的符号的个数

if(找到了特殊符号)
{
   则将List排序,得到最小的符号
}

else
{
   则没有符号,所以都作为默认的数据处理
}

最后我们需要去匹配这些特殊符号,

if(该符号为双引号)
{
   找到双引号以前的位置数据
   
//这个就是group1
   
   找到后双引号位置
    找到双引号位置内的数据
   
//这个就是group2
   
}
。。。。。。

通过这样的逻辑判断就简单地分出一个代码片段的组,group1和group2

循环流程:
由于程序不会只有一个目标符号,如:
string a1= "hello!";
string a2= "i love you!";
//string "a3";
上面实例则存在7个组
group1=string a1=
group2="hello!"
group3=;
group4=string a2= 
group5="i love you!"
group6=;
group7=//string "a3";
 
这样的组会存在多个,于是我们从目标字符串的0位置开始到它的长度进行循环(for(int i=0;i<code.length;i++)),得到多个的目标组。


该图展示了查找的判断逻辑,每找到一个组,则实例出RegexItem,放置到List<RegexItem>集合中。

List<RegexItem> items = new List<RegexItem>();
        
private int CreateItem(string code, int start)
        
{
            List
<RegexItem> regexs = new List<RegexItem>();
            RegexItem regx 
= null;

            
int count = 0;
            
int pos1 = code.IndexOf('"', start);
            
if (pos1 > -1)
            
{
                count
++;
                regx 
= new RegexItem();
                regx.Postion 
= pos1;
                regx.RegexMode 
= Mode.DoubleQuotedString;
                regexs.Add(regx);
            }

            
int pos2 = code.IndexOf(BeginSingleLineComments, start);
            
if (pos2 > -1)
            
{
                count
++;
                regx 
= new RegexItem();
                regx.Postion 
= pos2;
                regx.RegexMode 
= Mode.SingleLineComments;
                regexs.Add(regx);
            }

            
int pos3 = code.IndexOf(BeginMultiLineComments, start);
            
if (pos3 > -1)
            
{
                count
++;
                regx 
= new RegexItem();
                regx.Postion 
= pos3;
                regx.RegexMode 
= Mode.MultiLineComments;
                regexs.Add(regx);
            }

            
int pos4 = code.IndexOf("'", start);
            
if (pos4 > -1)
            
{
                count
++;
                regx 
= new RegexItem();
                regx.Postion 
= pos4;
                regx.RegexMode 
= Mode.SingleQuotedString;
                regexs.Add(regx);
            }

            RegexItem minItem 
= null;
            
if (count > 0)
            
{

                
if (regexs.Count > 1)
                
{
                    Comparison
<RegexItem> comp = new Comparison<RegexItem>(SortItmes);
                    regexs.Sort(comp);
                    minItem 
= regexs[0];
                }

                
else if (regexs.Count == 1)
                
{
                    minItem 
= regexs[0];
                }

            }

            
else
            
{
                minItem 
= new RegexItem();
                minItem.Postion 
= start;
                minItem.RegexMode 
= Mode.Default;
            }

            
int end = 0;


            RegexItem itemFirst 
= new RegexItem();
            itemFirst.RegexMode 
= Mode.Default;
            itemFirst.Postion 
= start;
            
if (minItem.RegexMode == Mode.DoubleQuotedString)
            
{
                end 
= code.IndexOf('"', minItem.Postion + 1);
                itemFirst.Text 
= code.Substring(start, minItem.Postion - start);
                items.Add(itemFirst);
                minItem.Text 
= code.Substring(minItem.Postion, end - minItem.Postion + 1);
                items.Add(minItem);
            }

            
else if (minItem.RegexMode == Mode.SingleLineComments)
            
{
                end 
= code.IndexOf(EndSingleLineComments, minItem.Postion + 1);
                
if (end == -1{ end = code.Length - 1; }//为最后一行
                else { end++; }//因为\r\n占两个字节

                itemFirst.Text 
= code.Substring(start, minItem.Postion - start);
                items.Add(itemFirst);
                minItem.Text 
= code.Substring(minItem.Postion, end - minItem.Postion + 1);
                items.Add(minItem);
            }

            
else if (minItem.RegexMode == Mode.MultiLineComments)
            
{
                end 
= code.IndexOf(EndMultiLineComments, minItem.Postion + 1);
                itemFirst.Text 
= code.Substring(start, minItem.Postion - start);
                items.Add(itemFirst);
                minItem.Text 
= code.Substring(minItem.Postion, end - minItem.Postion + 1);
                items.Add(minItem);
            }

            
else if (minItem.RegexMode == Mode.SingleQuotedString)
            
{
                end 
= code.IndexOf("'", minItem.Postion + 1);
                itemFirst.Text 
= code.Substring(start, minItem.Postion - start);
                items.Add(itemFirst);
                minItem.Text 
= code.Substring(minItem.Postion, end - minItem.Postion + 1);
                items.Add(minItem);
            }

            
else
            
{
                
// end = code.IndexOf(start, minItem.Postion - start + 1);
                end = code.Length - 1;
                minItem.Text 
= code.Substring(start, code.Length - start);
                items.Add(minItem);
            }


            
return end;
        }

public string GetHighLightCode(string code)
        
{
            
int i = 0;
            
//循环判断逻辑
            for (; i < code.Length; i++)
            
{
                
int start = CreateItem(code, i);
                i 
= start;
            }

            
        }


当然,如果没有源码的朋友可以到
http://www.cnblogs.com/KeithDan/archive/2008/04/23/1168279.html 去下载

posted on 2008-04-23 22:39  KeithDan  阅读(1957)  评论(5编辑  收藏  举报