正则表达式突出显示

时间:2016-12-26 22:08:06

标签: c# regex devexpress highlight

当我使用不同的正则表达式突出显示文档(RichEditControl)中的单词和注释(如SQL)时,我遇到了问题。

这是我的第一个正则表达式:

(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(--.*)

这适用于:/*blahblah*/--blahblah

我有另一个正则表达式:

((""(.|/[[:blank:]]/)*?"")|('(.|/[[:blank:]]/)*?'))

这适用于:'blahblah'(如sql string)

但是,如果我这样做:

'/*blahblah*/'

在我写下最后一个'之前,程序显示了一个异常:

  

发生了'System.ArgumentException'类型的未处理异常   DevExpress.Office.v15.2.Core.dll

提前感谢您的帮助。

这是完整的代码:

    private List<SyntaxHighlightToken> ParseTokens()
    {
        List<SyntaxHighlightToken> tokens = new List<SyntaxHighlightToken>();            
        DocumentRange[] ranges = null;            

        #region SearchSimpleCommas
        Regex quotations = new Regex(@"((""(.|/[[:blank:]]/)*?"")|('(.|/[[:blank:]]/)*?'))");
        ranges = document.FindAll(quotations);
        foreach (var range in ranges)
        {
            if (!IsRangeInTokens(range, tokens))
                tokens.Add(new SyntaxHighlightToken(range.Start.ToInt(), range.Length, StringSettings));   
        }
        #endregion

        #region SearchComment--/**/
        Regex comment = new Regex(@"(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(--.*)", RegexOptions.IgnoreCase | RegexOptions.Multiline);
        ranges = document.FindAll(comment);
        for (int i = 0; i < ranges.Length; i++)
        {
            tokens.Add(new SyntaxHighlightToken(ranges[i].Start.ToInt(), ranges[i].Length, CommentsSettings));
        }
        #endregion

        tokens.Sort(new SyntaxHighlightTokenComparer());
        // fill in gaps in document coverage
        AddPlainTextTokens(tokens);
        return tokens;
    }

    private void AddPlainTextTokens(List<SyntaxHighlightToken> tokens)
    {
        int count = tokens.Count;
        if (count == 0)
        {
            tokens.Add(new SyntaxHighlightToken(0, document.Range.End.ToInt(), defaultSettings));
            return;
        }
        tokens.Insert(0, new SyntaxHighlightToken(0, tokens[0].Start, defaultSettings));
        for (int i = 1; i < count; i++)
        {
            tokens.Insert(i * 2, new SyntaxHighlightToken(tokens[i * 2 - 1].End, tokens[i * 2].Start - tokens[i * 2 - 1].End, defaultSettings));
        }
        tokens.Add(new SyntaxHighlightToken(tokens[count * 2 - 1].End, document.Range.End.ToInt() - tokens[count * 2 - 1].End, defaultSettings));
    }

    private bool IsRangeInTokens(DocumentRange range, List<SyntaxHighlightToken> tokens)
    {
        return tokens.Any(t => IsIntersect(range, t));            
    }
    bool IsIntersect(DocumentRange range, SyntaxHighlightToken token)
    {
        int start = range.Start.ToInt();
        if (start >= token.Start && start < token.End)
            return true;
        int end = range.End.ToInt() - 1;
        if (end >= token.Start && end < token.End)
            return true;
        return false;
    }

    #region ISyntaxHighlightServiceMembers
    public void ForceExecute()
    {
        Execute();
    }
    public void Execute()
    {//The Exepction show in this part
        document.ApplySyntaxHighlight(ParseTokens());
    }
    #endregion

编辑:谢谢Harrison Mc。

我分享了我用过的代码,以防任何人需要它,只有我修改的代码(在方法ParseTokens中):

    #region SearchComments&Strings
    Regex definitiveRegex = new Regex(@"(?<string>'[^\\']*(?>\\.[^\\']*)*')|(?<comment>(?>/\*(?>[^*]|[\r\n]|(?>\*+(?>[^*/]|[\r\n])))*\*+/)|(?>--.*))");
    MatchCollection matches = definitiveRegex.Matches(document.Text);
    foreach (System.Text.RegularExpressions.Match match in matches)
    {
        try
        {
            System.Text.RegularExpressions.GroupCollection groups = match.Groups;
            if (groups["string"].Value.Length > 0)
            {
                ranges = null;
                for (int s = 0; s < groups.Count; s++)
                {
                    if (groups[s].Value != string.Empty)
                    {
                        ranges = document.FindAll(groups[s].Value, SearchOptions.None);
                        for (int z = 0; z < ranges.Length; z++)
                        {
                            if(!IsRangeInTokens(ranges[z], tokens))
                                tokens.Add(new SyntaxHighlightToken(ranges[z].Start.ToInt(), ranges[z].Length, StringSettings));
                        }
                    }
                }
            }
            else if (groups["comment"].Value.Length > 0)
            {
                ranges = null;
                for (int c = 0; c < groups.Count; c++)
                {
                    if (groups[c].Value != string.Empty)
                    {
                        ranges = document.FindAll(groups[c].Value.Trim(), SearchOptions.None);
                        for (int k = 0; k < ranges.Length; k++)
                        {
                            if (!IsRangeInTokens(ranges[k], tokens))
                                tokens.Add(new SyntaxHighlightToken(ranges[k].Start.ToInt(), ranges[k].Length, CommentsSettings));
                        }
                    }
                }
            }
        }
        catch(Exception ex){ }
    }
    #endregion

1 个答案:

答案 0 :(得分:0)

为了避免在注释中突出显示字符串和字符串中的注释,您需要某种“状态”,正则表达式无法轻易地为您提供。对于单个字符串和注释正则表达式来说,这些情况很难处理,因为它需要跟踪您在查找字符串时是否处于注释中,反之亦然。

"This string looks like it contains a /*comment*/ but it does not."
/* This comment looks like it contains a 'string' but it does not. */

但是,如果你使用一个对匹配字符串和注释具有不同组的正则表达式,那么贪婪的字符消耗会阻止字符串中的“注释”或注释中的“字符串”搞乱。

我测试了这个正则表达式,它似乎适用于字符串中的“注释”和注释中的“字符串”(都有多行)。

(?<string>'[^\\']*(?>\\.[^\\']*)*'|""[^\\""]*(?>\\.[^\\""]*)*"")|(?<comment>(?>/\*(?>[^*]|[\r\n]|(?>\*+(?>[^*/]|[\r\n])))*\*+/)|(?>--.*))

这里的关键是正则表达式跟踪“状态”,该状态决定我们是在字符串的中间还是在评论的中间。

要使用此功能,您需要从整体匹配中抓取各个组。 (?<name>group)语法创建一个命名组,您可以在以后提取该组。如果<string>组匹配,那么它就是一个字符串,如果<comment>组匹配,则表示评论。由于我不熟悉document.FindAll方法,因此我使用regex.Matches方法从.NET文档中采用了一个示例:

Regex stringAndCommentRegex = new Regex(@"(?<string>'[^\\']*...");
MatchCollection matches = stringAndCommentRegex.Matches(text);
foreach (Match match in matches)
{
    GroupCollection groups = match.Groups;
    if (match.groups["string"].Value.Length > 0)
    {
        // handle string
    }
    else if (match.groups["comment"].Value.Length > 0)
    {
        // handle comment
    }
}

希望这有帮助!

P.S。我使用regex101.com测试正则表达式,但为了这样做,我不得不逃避正斜杠而不是逃避双引号。我尽力将它们重新加入,但我可能错过了一两个。

参考文献: