当我使用不同的正则表达式突出显示文档(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
答案 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测试正则表达式,但为了这样做,我不得不逃避正斜杠而不是逃避双引号。我尽力将它们重新加入,但我可能错过了一两个。
参考文献: