Regex для выделения

У меня есть проблема, когда я использую различные regex, чтобы выделить слова и комментарии в документе (RichEditControl), как SQL.

Это мое первое регулярное выражение:

(/*([^*]|[rn]|(*+([^*/]|[rn])))**+/)|(--.*)

Это работает хорошо В: /*blahblah*/и --blahblah

И у меня есть еще одно regex:

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

Это хорошо работает в: 'blahblah'(как строка sql)

Но, если я это сделаю:

'/*blahblah*/'

Перед тем как я напишу последнюю 'программу покажите мне исключение:

Необработанное исключение типа ‘ System.ArgumentException ‘ произошло в
DevExpress.Офис.v15.2.Ядро.файл 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(@"(/*([^*]|[rn]|(*+([^*/]|[rn])))**+/)|(--.*)", 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

EDIT: спасибо Harrison Mc.

Я делюсь кодом, который я использовал в случае, если кому-то это нужно, только то, что я изменил (внутри метода ParseTokens):

    #region SearchComments&Strings
    Regex definitiveRegex = new Regex(@"(?<string>'[^']*(?>.[^']*)*')|(?<comment>(?>/*(?>[^*]|[rn]|(?>*+(?>[^*/]|[rn])))**+/)|(?>--.*))");
    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 ответ

  1. Чтобы избежать выделения комментариев в строках и строк в комментариях, вам нужно какое-то» состояние», которое регулярные выражения не могут легко дать вам. Эти ситуации были бы трудными для отдельных регулярных выражений строки и комментария, чтобы иметь дело, потому что это потребовало бы отслеживания того, находитесь ли вы в комментарии при поиске строки и наоборот.

    "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методом, я принял пример из документации .NET с помощью regex.Matchesметода:

    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 чтобы проверить regex, но для этого я должен был избежать косых линий и не избежать двойных кавычек. Я старался изо всех сил, чтобы добавить их обратно, но я, возможно, пропустил один или два.

    Ссылки на литературу: