Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C#中解析此字符串的最佳方法是什么?_C#_.net_String_Parsing - Fatal编程技术网

在C#中解析此字符串的最佳方法是什么?

在C#中解析此字符串的最佳方法是什么?,c#,.net,string,parsing,C#,.net,String,Parsing,我有一个从另一个系统读取的字符串。它基本上是一个长字符串,表示由空格分隔的键值对列表。看起来是这样的: key:value[space]key:value[space]key:value[space] 所以我写了这段代码来解析它: string myString = ReadinString(); string[] tokens = myString.split(' '); foreach (string token in tokens) { string key = token.

我有一个从另一个系统读取的字符串。它基本上是一个长字符串,表示由空格分隔的键值对列表。看起来是这样的:

 key:value[space]key:value[space]key:value[space]
所以我写了这段代码来解析它:

string myString = ReadinString();
string[] tokens = myString.split(' ');
foreach (string token in tokens) {
     string key = token.split(':')[0];
     string value = token.split(':')[1];
     .  . . . 
}
现在的问题是,一些值中有空格,因此我在顶部的“简单化”拆分不再有效。我想看看我如何仍然可以解析出键值对列表(给定空格作为分隔符),现在我知道值字段中也可能有空格,因为split似乎不再能够工作了


注意:我现在确认键中没有空格,所以我只需要担心值。抱歉造成混淆。

您可以尝试在空格(键和值,而不是:符号)之间对内容进行Url编码,但这需要您控制输入方法

或者您可以简单地使用另一种格式(如XML或JSON),但同样需要控制输入格式

如果您无法控制输入格式,您可以始终使用正则表达式搜索单词plus:后面的单个空格

更新(感谢Jon Grant)
看起来键和值中可以有空格。如果是这种情况,你需要认真重新考虑你的策略,因为即使是正则表达式也不会有帮助。

我想你可以采用你的方法,稍微扩展一下,来处理这些事情

伪代码类型:

List<string> parsedTokens = new List<String>();
string[] tokens = myString.split(' ');
for(int i = 0; i < tokens.Length; i++)
{
    // We need to deal with the special case of the last item, 
    // or if the following item does not contain a colon.
    if(i == tokens.Length - 1 || tokens[i+1].IndexOf(':' > -1)
    {
        parsedTokens.Add(tokens[i]);
    }
    else
    {
        // This bit needs to be refined to deal with values with multiple spaces...
        parsedTokens.Add(tokens[i] + " " + tokens[i+1]);
    }
}
List parsedTokens=new List();
string[]tokens=myString.split(“”);
for(int i=0;i-1)
{
Add(tokens[i]);
}
其他的
{
//需要对该位进行优化,以处理具有多个空格的值。。。
Add(tokens[i]+“”+tokens[i+1]);
}
}
另一种方法是在冒号上拆分…这样,第一个数组项将是第一个键的名称,第二个数组项将是第一个键的值,然后是第二个键的名称(可以使用LastIndexOf将其拆分),等等。如果值可以包含冒号,或者键可以包含空格,这显然会变得非常混乱,但在这种情况下,您将非常不走运

string input = "key1:value key2:value key3:value";
Dictionary<string, string> dic = input.Split(' ').Select(x => x.Split(':')).ToDictionary(x => x[0], x => x[1]);
然后是一组数组:

{ "key", "value" }, { "key", "value" }
然后是一本字典:

"key" => "value", "key" => "value"

请注意,
Dictionary
不允许重复键,在这种情况下会引发异常。如果可能出现这种情况,请使用
ToLookup()

如果不将分割从一个空格更改为另一个空格(如“|”)则无法工作

考虑这一点:

阿尔弗雷德·贝斯特:阿尔弗雷德·贝斯特阿尔弗雷德:阿尔弗雷德·贝斯特

  • 这是键“阿尔弗雷德·贝斯特”和值“阿尔弗雷德”还是键“阿尔弗雷德”和值“贝斯特·阿尔弗雷德”

使用此正则表达式:

\w+:[\w\s]+(?![\w+:])
我试过了

test:testvalue test2:test value test3:testvalue3
它返回三个匹配项:

test:testvalue
test2:test value
test3:testvalue3
您可以将
\w
更改为输入中可能出现的任何字符集

用于测试此功能的代码:

var regex = new Regex(@"\w+:[\w\s]+(?![\w+:])");
var test = "test:testvalue test2:test value test3:testvalue3";

foreach (Match match in regex.Matches(test))
{
    var key = match.Value.Split(':')[0];
    var value = match.Value.Split(':')[1];

    Console.WriteLine("{0}:{1}", key, value);
}
Console.ReadLine();
正如神智健全的Wonko所指出的,这个正则表达式将在带有
的值上失败。如果您预测到这种情况,请使用
\w+:[\w:+?(?![\w+:])
作为正则表达式。但是,当
值中的冒号前面有空格时,这仍然会失败……我会考虑解决方法。

这段代码可以做到这一点(给定以下规则)。它解析键和值,并以
命令式
数据结构返回它们。我在结尾添加了一些代码,假设给定示例,整个字符串/流的最后一个值将附加一个[space]:

private Dictionary<string, string> ParseKeyValues(string input)
        {
            Dictionary<string, string> items = new Dictionary<string, string>();

            string[] parts = input.Split(':');

            string key = parts[0];
            string value;

            int currentIndex = 1;

            while (currentIndex < parts.Length-1)
            {
                int indexOfLastSpace=parts[currentIndex].LastIndexOf(' ');
                value = parts[currentIndex].Substring(0, indexOfLastSpace);
                items.Add(key, value);
                key = parts[currentIndex].Substring(indexOfLastSpace + 1);
                currentIndex++;
            }
            value = parts[parts.Length - 1].Substring(0,parts[parts.Length - 1].Length-1);


            items.Add(key, parts[parts.Length-1]);

            return items;

        }
专用字典ParseKeyValue(字符串输入)
{
字典项=新字典();
string[]parts=input.Split(“:”);
字符串键=部件[0];
字符串值;
int currentIndex=1;
而(当前索引<零件长度-1)
{
int indexOfLastSpace=零件[currentIndex].LastIndexOf(“”);
值=零件[currentIndex]。子字符串(0,indexOfLastSpace);
项目。添加(键、值);
键=部件[currentIndex]。子字符串(indexOfLastSpace+1);
currentIndex++;
}
值=零件[parts.Length-1]。子字符串(0,零件[parts.Length-1]。长度-1);
添加项目(图例、零件[零件长度-1]);
退货项目;
}
注意:此算法假定以下规则:

  • 值中没有空格
  • 钥匙上没有冒号
  • 值中没有冒号

  • 使用正则表达式可以解决您的问题:

    private void DoSplit(string str)
    {
        str += str.Trim() + " ";
        string patterns = @"\w+:([\w+\s*])+[^!\w+:]";
        var r = new System.Text.RegularExpressions.Regex(patterns);
        var ms = r.Matches(str);
        foreach (System.Text.RegularExpressions.Match item in ms)
        {
            string[] s = item.Value.Split(new char[] { ':' });
            //Do something
        }
    }
    
    给你:

    foo = Foobarius Maximus Tiberius Kirk
    bar = Barforama
    zap = Zip Brannigan
    

    没有任何正则表达式或字符串concat,并且作为可枚举项(假定键没有空格,但值可以):

    公共静态IEnumerable拆分(字符串文本)
    {
    if(text==null)
    屈服断裂;
    int keyStart=0;
    int keyEnd=-1;
    int lastSpace=-1;
    for(int i=0;i=0)
    {
    返回新的KeyValuePair(text.Substring(keyStart,keyEnd-keyStart),text.Substring(keyEnd+1,lastSpace-keyEnd-1));
    keyStart=lastSpace+1;
    }
    keyEnd=i;
    继续;
    }
    }
    如果(keyEnd>=0)
    返回新的KeyValuePair(text.Substring(keyStart,keyEnd-keyStart),text.Substring(keyEnd+1));
    }
    
    您可以控制输入吗
    string input = "foo:Foobarius Maximus Tiberius Kirk bar:Barforama zap:Zip Brannigan";
    
    foreach (Match match in Regex.Matches(input, @"(\w+):([^:]+)(?![\w+:])"))
    {
       Console.WriteLine("{0} = {1}", 
           match.Groups[1].Value, 
           match.Groups[2].Value
          );
    }
    
    foo = Foobarius Maximus Tiberius Kirk
    bar = Barforama
    zap = Zip Brannigan
    
        public static IEnumerable<KeyValuePair<string, string>> Split(string text)
        {
            if (text == null)
                yield break;
    
            int keyStart = 0;
            int keyEnd = -1;
            int lastSpace = -1;
            for(int i = 0; i < text.Length; i++)
            {
                if (text[i] == ' ')
                {
                    lastSpace = i;
                    continue;
                }
    
                if (text[i] == ':')
                {
                    if (lastSpace >= 0)
                    {
                        yield return new KeyValuePair<string, string>(text.Substring(keyStart, keyEnd - keyStart), text.Substring(keyEnd + 1, lastSpace - keyEnd - 1));
                        keyStart = lastSpace + 1;
                    }
                    keyEnd = i;
                    continue;
                }
            }
            if (keyEnd >= 0)
                yield return new KeyValuePair<string, string>(text.Substring(keyStart, keyEnd - keyStart), text.Substring(keyEnd + 1));
        }