在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));
}