2016-12-26 12 views
0

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

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

(/\*([^*]|[\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 

EDIT: Спасибо Харрисон 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 
+0

Я не знаю, что это проблема * (я слишком устал для этого:)) *, но: '[^ *] 'уже включает CR и LF, вам не нужно добавлять' | [\ r \ n] '. Простой шаблон для сопоставления C-многострочных комментариев: '/ \ * [^ *] * (?> \ * + (?! /) [^ *] *) * \ * /' –

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

Ссылки:

+0

Спасибо! пример и ссылки были очень полезными. Мне пришлось смешивать оба способа haha ​​xD (пример ура и метод FindAll), но теперь все работает правильно. Теперь я буду искать способ, которым процесс не замедляет редактор, поскольку он всегда выполняет поиск всего документа. Опять же, спасибо! : D – Guharo