我有一个使用RichTextBox的自定义日志窗口,我在其中突出显示来自第三方控制台应用程序的日志消息(在带有标准输入/错误重定向的<div class="form-group">
<label class="control-label">First Name</label>
<input class="form-control" type="text" data-filter="0">
</div>
中运行)。
日志消息如下所示:
Process
我想根据输出类型([Info] Bla bla bla
[Status] Bla bla bla
[SQL] Bla bla bla
,[Info]
,[Status]
等来突出显示文本...),所以我写了几行代码来确定消息颜色:
[SQL]
这几乎正常。当输出消息包含多个这样的状态时会发生此问题,例如:
// Workout message colour
Color messageColor = normalText;
if (outputMessage.Contains("[SQL]"))
messageColor = sqlText;
else if (outputMessage.Contains("[Status]"))
messageColor = statusText;
else if (outputMessage.Contains("[Warning]"))
messageColor = warningText;
else if (outputMessage.Contains("[Notice]"))
messageColor = noticeText;
else if (outputMessage.Contains("[Debug]"))
messageColor = debugText;
else if (outputMessage.Contains("[Error]"))
messageColor = errorText;
else if (outputMessage.Contains("[Note]"))
messageColor = statusText;
else
messageColor = normalText;
我希望它仅应用[Info]: [SQL]: Connecting to the Log Database
状态的颜色,但它似乎应用了[Info]
状态的颜色,如下所示:
有更好的方法吗?即只检测第一次出现的状态?或者是我唯一的选择来处理if语句以尝试按照我希望它被检测到的顺序来适应它?
这是我完整的代码片段,它处理日志写入自定义输出RTB:
[SQL]
答案 0 :(得分:1)
如果要查找最接近字符串开头的术语,则不能使用Contains
,因为它不会告诉您字符串中术语的位置。要做到这一点,你将不得不对字符串中每个术语的位置进行排序,并选择第一个术语。您可以在LINQ中执行以下操作:
var termHighlight = new Dictionary<string, Color>();
termHighlight.Add("SQL", sqlColor);
termHighlight.Add("Status", statusColor);
...
var keyIndexes = termHighlight.Select(t => new { Key = t.Key, Index = outputMessage.IndexOf('[' + t.Key + ']')}).Where(t => t.Index >= 0);
return keyIndexes.Any() ? termHighlight[keyIndexes.OrderBy(a => a.Index).First().Key] : Color.Black; // last is default color
答案 1 :(得分:0)
为什么不简单地找到您感兴趣的子字符串?例如:
view.bringToFront();
但是,如果您想要尽可能少地更改代码的选项,则应使用this.UIThread(() =>
{
// Workout message colour
Color messageColor = normalText;
int closingBracketIndex = outputMessage.IndexOf(']');
if (closingBracketIndex > 2)
{
string msgType = outputMessage.Substring(1, closingBracketIndex - 1);
switch (msgType)
{
case "SQL": messageColor = sqlText;
break;
case "Status": messageColor = statusText;
break;
case "Warning": messageColor = warningText;
break;
case "Notice": messageColor = noticeText;
break;
case "Debug": messageColor = debugText;
break;
case "Error": messageColor = errorText;
break;
case "Note": messageColor = statusText;
break;
}
}
// Format message
outputMessage = FormatOutput(outputMessage);
// Append message with colour
RTBAppendText(targetRTB, messageColor, outputMessage);
...
}
更改Contains
并在StartsWith
之前移动FormatOutput
行。< / p>
选项2
在Dour的回答中受到启发,我想添加另一个使用RTBAppendText
的选项:
首先,在您的班级中拥有此私人财产:
Dictionary
其次,将其添加到您的类'构造函数:
private Dictionary<string, Color> typeColors;
然后,您的代码可以像这样简单(和可读):
typeColors = new Dictionary<string, Color>();
typeColors.Add("SQL", sqlText); // Just place here the color instead of using sqlText
typeColors.Add("Status", statusText); // Just place here the color instead of using statusText
...
typeColors.Add("Default", normalText); // Just place here the color instead of using normalText
答案 2 :(得分:0)
你永远不会贬低&#34; [信息]&#34;状态。 当你把它作为第一个&#34;如果&#34;,&#34; else&#34;语句不会被命中。
// Workout message colour
Color messageColor;
If (outputMessage.Contains("[Info]"))
messageColor=normalText;
if (outputMessage.Contains("[SQL]"))
messageColor = sqlText;
else if (outputMessage.Contains("[Status]"))
messageColor = statusText;
else if (outputMessage.Contains("[Warning]"))
messageColor = warningText;
else if (outputMessage.Contains("[Notice]"))
messageColor = noticeText;
else if (outputMessage.Contains("[Debug]"))
messageColor = debugText;
else if (outputMessage.Contains("[Error]"))
messageColor = errorText;
else if (outputMessage.Contains("[Note]"))
messageColor = statusText;
else
messageColor = normalText;
答案 3 :(得分:0)
做一些像使用正则表达式的东西:
var regex = new System.Text.RegularExpressions.Regex(@"^\[ \d{2}:\d{2}:\d{2} \] (\[\w+\])");
var match = regex.Match("[ 22:11:22 ] [Info]: [SQL] Blah");
if (string.Equals(match.Groups[1], "[Info]")) {
...
}
答案 4 :(得分:0)
您可以为每个状态及其特殊化实现基类:
public abstract class Status
{
public abstract Color Color { get; }
public abstract string Pattern { get; }
public int GetIndex(string lookup)
{
return lookup.IndexOf(Pattern);
}
}
public class StatusSql : Status
{
public override Color Color{ get; } = Color.Red;
public override string Pattern { get; } = "[SQL]";
}
public class StatusInfo : Status
{
public override Color Color { get; } = Color.White;
public override string Pattern { get; } = "[INFO]";
}
您还应该为每个其他状态实现一个类。
然后你可以实现一种方法来检查该状态的第一次出现:
private static Color GetFirstStatusColor(string test)
{
List<Status> status = new List<Status>();
status.Add(new StatusSql());
status.Add(new StatusInfo());
int currentMin = -1;
bool foundOne = false;
Status firstStatus = null;
foreach(var stat in status)
{
int currStatusIndex = stat.GetIndex(test);
if ((currStatusIndex < currentMin) || (!foundOne && currStatusIndex != -1))
{
firstStatus = stat;
currentMin = currStatusIndex;
foundOne = true;
}
}
return firstStatus != null ? firstStatus.Color : Color.White;
}
然后这段代码:
Color messageColor = normalText;
if (outputMessage.Contains("[SQL]"))
messageColor = sqlText;
else if (outputMessage.Contains("[Status]"))
messageColor = statusText;
else if (outputMessage.Contains("[Warning]"))
messageColor = warningText;
else if (outputMessage.Contains("[Notice]"))
messageColor = noticeText;
else if (outputMessage.Contains("[Debug]"))
messageColor = debugText;
else if (outputMessage.Contains("[Error]"))
messageColor = errorText;
else if (outputMessage.Contains("[Note]"))
messageColor = statusText;
else
messageColor = normalText;
可以成为这个:
Color messageColor = GetFirstStatusColor(outputMessage);
这样,如果您想要更改决定要显示的颜色的方式,它将包含在一个地方。
您可以定义具有此责任性的StatusList类,而不是静态方法:
public class StatusList : List<Status>
{
public Status GetFirstFoundStatus(string lookup)
{
int currentMin = -1;
bool foundOne = false;
Status firstStatus = null;
foreach (var stat in this)
{
int currStatusIndex = stat.GetIndex(lookup);
if ((currStatusIndex < currentMin) || (!foundOne && currStatusIndex != -1))
{
firstStatus = stat;
currentMin = currStatusIndex;
foundOne = true;
}
}
return firstStatus;
}
}
然后你可以像这样使用它:
StatusList statusList = new StatusList();
statusList.Add(new StatusSql());
statusList.Add(new StatusInfo());
var status = statusList.GetFirstFoundStatus(test);
return status != null ? status.Color : Color.White;
更好的方法是实现工厂而不是该列表:
public class StatusFactory
{
private List<Status> _possibleStatus;
public StatusFactory()
{
_possibleStatus = new List<Status>();
_possibleStatus.Add(new StatusInfo());
_possibleStatus.Add(new StatusSql());
_possibleStatus.Add(new StatusDefault());
}
public StatusFactory(IEnumerable<Status> possibleStatus)
{
_possibleStatus = new List<Status>();
_possibleStatus.AddRange(possibleStatus);
}
public Status BuildMessageStatus(string message)
{
int currentIndex = -1;
Status messageStatus = new StatusDefault();
foreach(var status in _possibleStatus)
{
var statusIndex = status.GetIndex(message);
if(statusIndex > -1 && ((currentIndex != -1 && statusIndex < currentIndex) || (currentIndex == -1)))
{
currentIndex = statusIndex;
messageStatus = status;
}
}
return messageStatus;
}
}
注意我已经定义了一个DefaultStatus,以防我们在字符串中找不到正确的Pattern:
public class StatusDefault : Status
{
public override Color Color { get; } = Color.White;
protected override string Pattern { get; } = string.Empty;
public override int GetIndex(string lookup)
{
return -1;
}
}
我还在基类中创建了GetIndex方法virtual,并将Pattern属性的访问修饰符更改为protected。
使用代码的当前状态是:
StatusFactory factory = new StatusFactory();
Status status = factory.BuildMessageStatus(test);
Color messageColor = status.Color;