使用string.contains函数检查C#中第一次出现的字符串

时间:2016-07-28 01:15:07

标签: c# string

我有一个使用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]状态的颜色,如下所示:

enter image description here

有更好的方法吗?即只检测第一次出现的状态?或者是我唯一的选择来处理if语句以尝试按照我希望它被检测到的顺序来适应它?

这是我完整的代码片段,它处理日志写入自定义输出RTB:

[SQL]

5 个答案:

答案 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;

编辑2

更好的方法是实现工厂而不是该列表:

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;