如何在C#中解析包含多个标记和多个定界符的字符串?

时间:2019-07-16 16:55:29

标签: c# parsing

我要解析的字符串(又称消息)看起来像这样。 (当将其粘贴到记事本中时,它看起来也完全像这样

"CorrelationId: b99fb632-78cf-4910-ab23-4f69833ed2d9
Request for API: /api/acmsxdsreader/readpolicyfrompolicyassignment Caller:C2F023C52E2148C9C1D040FBFAC113D463A368B1 CorrelationId: b99fb632-78cf-4910-ab23-4f69833ed2d9 RequestedSchemas: {urn:schema:Microsoft.Rtc.Management.Policy.Voice.2008}VoicePolicy, {urn:schema:Microsoft.Rtc.Management.Policy.Voice.2008}OnlineVoiceRoutingPolicy,  TenantId: 7a205197-8e59-487d-b9fa-3fc1b108f1e5"

我想制作5个单独的函数,以返回每个特定值,例如GetCorrelationIdGetRFAPIGetCallerGetRqSchema和{{1 }}并提取它们对应的值。

在不使用Regex的情况下如何在C#中执行此操作?

下面是我为调用者编写的代码(此方法对于所有其他4个函数都是相同的),但是我被告知正则表达式很慢,不应由我的指导者使用,而我下面的方法不会无论如何都没有工作。另外,我尝试使用正则表达式的最大问题是消息中有多个定界符,例如GetTenantId

',' ' ' and ': ' and ':'

预期结果应该是:

string parseCaller(string message)
            {
                var pattern = @"Caller:(.*)";
                var r = new Regex(pattern).Match(message);
                var caller = r.Groups[1].Value;

                return caller;
            }

3 个答案:

答案 0 :(得分:3)

我会稍微有所不同,并创建一个类,该类具有要从字符串解析的每个值的属性。然后,我们可以创建一个静态Parse方法,该方法从输入字符串创建该类的实例,从而为您设置所有属性。

如果字符串始终具有相同顺序的相同项目(CorrelationId,RequestForAPI,Caller等),我们可以利用简单的帮助程序方法来GetValueBetween两个标头。

代码非常简单:

class MessageData
{
    public string CorrelationId { get; set; }
    public string RequestForAPI { get; set; }
    public string RequestedSchemas { get; set; }
    public string Caller { get; set; }
    public string TennantId { get; set; }

    public static MessageData Parse(string input)
    {
        return new MessageData
        {
            CorrelationId = GetValueBetween(input, "CorrelationId:", "Request for API:"),
            RequestForAPI = GetValueBetween(input, "Request for API:", "Caller:"),
            Caller = GetValueBetween(input, "Caller:", "CorrelationId:"),
            RequestedSchemas = GetValueBetween(input, "RequestedSchemas:", "TenantId:"),
            TennantId = GetValueBetween(input, "TenantId:", null),
        };
    }

    private static string GetValueBetween(string input, string startDelim, string endDelim)
    {
        if (input == null) return string.Empty;
        var start = input.IndexOf(startDelim);
        if (start == -1) return string.Empty;
        start += startDelim.Length;
        var length = endDelim == null 
            ? input.Length - start 
            : input.IndexOf(endDelim, start) - start;
        if (length < 0) length = input.Length - start;
        return input.Substring(start, length).Trim();           
    }
}

现在我们可以调用MessageData.Parse(inputString),我们有了一个类,它的所有属性都通过输入字符串设置:

private static void Main()
{
    var message = @"CorrelationId: b99fb632-78cf-4910-ab23-4f69833ed2d9
            Request for API: /api/acmsxdsreader/readpolicyfrompolicyassignment Caller:C2F023C52E2148C9C1D040FBFAC113D463A368B1 CorrelationId: b99fb632-78cf-4910-ab23-4f69833ed2d9 RequestedSchemas: {urn:schema:Microsoft.Rtc.Management.Policy.Voice.2008}VoicePolicy, {urn:schema:Microsoft.Rtc.Management.Policy.Voice.2008}OnlineVoiceRoutingPolicy,  TenantId: 7a205197-8e59-487d-b9fa-3fc1b108f1e5";

    var messageData = MessageData.Parse(message);

    // Now we can access any property
    Console.WriteLine(messageData.CorrelationId);
    Console.WriteLine(messageData.RequestForAPI);
    Console.WriteLine(messageData.RequestedSchemas);
    Console.WriteLine(messageData.Caller);
    Console.WriteLine(messageData.TennantId);

    Console.ReadKey();
}

答案 1 :(得分:1)

根据您提出的问题中的这些规范:

  

在不使用Regex的情况下如何在C#中执行此操作?

  

我想做5个独立的功能

您可以尝试以下方法。这非常简单,因为您可以研究字符串并适当使用IndexOfSubString函数:

using System;
class ParseTest
{
    static string GetCorrelationId(string message)
    {
        int i = message.IndexOf(": ") + 2; //length of ": "
        int j = message.IndexOf("Request");
        return message.Substring(i, j-i).Trim();
    }

    static string GetRFAPI(string message)
    {
        int i = message.IndexOf("API: ") + 5; //length of "API: "
        int j = message.IndexOf("Caller");
        return message.Substring(i, j-i).Trim();
    }

    static string GetCaller(string message)
    {
        int i = message.IndexOf("Caller:") + 7; //length of "Caller: "
        int j = message.IndexOf(" CorrelationId");
        return message.Substring(i, j-i).Trim();
    }

    static string GetRqSchema(string message)
    {
        int i = message.IndexOf("RequestedSchemas:") + 17; //length of "RequestedSchemas:"
        int j = message.IndexOf(",  TenantId:");
        return message.Substring(i, j-i).Trim();
    }

    static string GetTenantId(string message)
    {
        int i = message.IndexOf("TenantId:") + 9; //length of "TenantId: "
        return message.Substring(i).Trim();
    }

    static void Main()
    {
        string m = @"CorrelationId: b99fb632-78cf-4910-ab23-4f69833ed2d9
                    Request for API: /api/acmsxdsreader/readpolicyfrompolicyassignment Caller:C2F023C52E2148C9C1D040FBFAC113D463A368B1 CorrelationId: b99fb632-78cf-4910-ab23-4f69833ed2d9 RequestedSchemas: {urn:schema:Microsoft.Rtc.Management.Policy.Voice.2008}VoicePolicy, {urn:schema:Microsoft.Rtc.Management.Policy.Voice.2008}OnlineVoiceRoutingPolicy,  TenantId: 7a205197-8e59-487d-b9fa-3fc1b108f1e5";
        Console.WriteLine(GetCorrelationId(m));
        Console.WriteLine(GetRFAPI(m));
        Console.WriteLine(GetCaller(m));
        Console.WriteLine(GetRqSchema(m));
        Console.WriteLine(GetTenantId(m));
    }
}

您可以here运行它。

编辑:当然,您可以将其修改为使用仅获取属性,就像其他一些回答者试图做的那样。

另一方面,如果您想编写一个解析器(这是一个懒惰的人?),那么您的研究乐趣又是另一回事。

答案 2 :(得分:1)

如果您不知道将来从API返回的这些元素的顺序是否会更改,这是一个更可靠的解决方案:

private string GetRFAPI(string str)
{
    return GetSubstring(str, "Request for API: ", ' ', 1);
}

private string GetCaller(string str)
{
    return GetSubstring(str, "Caller:", ' ', 1);
}

private string GetCorrelationId(string str)
{
    return GetSubstring(str, "CorrelationId: ", ' ', 1);
}

private string GetTenantId(string str)
{
    return GetSubstring(str, "TenantId: ", ' ', 1);
}

private string GetRequestedSchemas(string str)
{
    return GetSubstring(str, "RequestedSchemas: ", ',', 2);
}

private string GetSubstring(string str, string pattern, char delimiter, int occurrence)
{
    int start = str.IndexOf(pattern);
    if (start < 0)
    {
        return null;
    }

    for (int i = start + pattern.Length, counter = 0; i < str.Length; i++, counter++)
    {
        if ((str[i] == delimiter && --occurrence == 0) || i == str.Length - 1)
        {
            return str.Substring(start + pattern.Length, counter).Trim();
        }
    }

    return null;
}