在 C# 中解析此字符串的最佳方法是什么
本文关键字:最佳 方法 是什么 字符串 | 更新日期: 2023-09-27 17:58:15
我有一个字符串,我正在从另一个系统读取。它基本上是一个长字符串,表示由中间空格分隔的键值对列表。它看起来像这样:
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];
. . . .
}
现在的问题是某些值中有空格,因此我在顶部的"简单"拆分不再有效。我想看看我如何仍然可以解析出键值对列表(给定空格作为分隔符(,因为我知道值字段中也可能有空格,因为拆分似乎不再能够工作。
注意:我现在确认 KEY 中没有空格,所以我只需要担心值。对混乱表示歉意。
使用以下正则表达式:
'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 the Sane 指出的那样,此正则表达式将在具有 :
的值上失败。如果预测这种情况,请使用 'w+:['w: ]+?(?!['w+:])
作为正则表达式。不过,当 value
中的冒号前面有空格时,这仍然会失败......我会考虑解决这个问题。
如果不将拆分从空格更改为其他内容(例如"|"(,则无法正常工作。
考虑一下:
阿尔弗雷德·贝斯特:阿尔弗雷德·贝斯特 阿尔弗雷德:阿尔弗雷德·贝斯特
- 这是钥匙"阿尔弗雷德·贝斯特"和价值阿尔弗雷德"还是钥匙"阿尔弗雷德">
- 和价值"贝斯特·阿尔弗雷德"?
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
您可以尝试对空格之间的内容进行 Url 编码(键和值而不是 : 符号(,但这需要您控制输入法。
或者你可以简单地使用另一种格式(如XML或JSON(,但同样你需要控制输入格式。
如果您无法控制输入格式,则始终可以使用正则表达式,并搜索单词加号:后面的单个空格。
更新(感谢乔恩格兰特(看起来您可以在键和值中包含空格。如果是这种情况,您将需要认真重新考虑您的策略,因为即使是正则表达式也无济于事。
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" }
然后是字典:
"key" => "value", "key" => "value"
请注意,Dictionary<K,V>
不允许重复的密钥,在这种情况下会引发异常。如果可能出现这种情况,请使用 ToLookup()
。
使用正则表达式可以解决您的问题:
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
}
}
此代码将执行此操作(给定以下规则(。 它分析键和值,并以Dictonary<string, string>
数据结构返回它们。 我在最后添加了一些代码,假设给定您的示例,整个字符串/流的最后一个值将附加一个 [空格]:
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;
}
注意:此算法假定以下规则:
- 值中没有空格
- 键中没有冒号
- 值中没有冒号
没有任何正则表达式或字符串连接,并且作为可枚举对象(它假设键没有空格,但值可以(:
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));
}
我想你可以采用你的方法并稍微扩展它来处理这些东西......
伪代码种类:
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]);
}
}
另一种方法是在冒号上分裂... 这样,您的第一个数组项将是第一个键的名称,第二项将是第一个键的值,然后是第二个键的名称(可以使用 LastIndexOf 将其拆分出来(,依此类推。如果值可以包含冒号,或者键可以包含空格,这显然会变得非常混乱,但在这种情况下,您将几乎不走运......