我有以下逗号分隔的字符串,我需要拆分.问题是某些内容在引号内并包含不应在分割中使用的逗号...
串:
111,222,"33,44,55",666,"77,88","99"
Run Code Online (Sandbox Code Playgroud)
我想要输出:
111
222
33,44,55
666
77,88
99
Run Code Online (Sandbox Code Playgroud)
我试过这个:
(?:,?)((?<=")[^"]+(?=")|[^",]+)
Run Code Online (Sandbox Code Playgroud)
但它读取"77,88","99"之间的逗号作为命中,我得到以下输出:
111
222
33,44,55
666
77,88
,
99
Run Code Online (Sandbox Code Playgroud)
有谁能够帮我?我用完了几个小时...... :) /彼得
jim*_*ode 85
根据您的需要,您可能无法使用csv解析器,实际上可能想要重新发明轮子!
您可以使用一些简单的正则表达式来完成
(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)
Run Code Online (Sandbox Code Playgroud)
这将执行以下操作:
(?:^|,)=匹配表达式"行或字符串的开头,"
(\"(?:[^\"]+|\"\")*\"|[^,]*) =编号的捕获组,这将在2个备选项之间进行选择:
这应该可以为您提供所需的输出.
C#中的示例代码
static Regex csvSplit = new Regex("(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)", RegexOptions.Compiled);
public static string[] SplitCSV(string input)
{
List<string> list = new List<string>();
string curr = null;
foreach (Match match in csvSplit.Matches(input))
{
curr = match.Value;
if (0 == curr.Length)
{
list.Add("");
}
list.Add(curr.TrimStart(','));
}
return list.ToArray();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine(SplitCSV("111,222,\"33,44,55\",666,\"77,88\",\"99\""));
}
Run Code Online (Sandbox Code Playgroud)
警告根据@MrE的评论 - 如果一个流氓的新行字符出现在一个格式错误的csv文件中并且你最终得到一个不均匀的("字符串")你会得到灾难性的回溯(https://www.regular-expressions.info/ catastrophic.html)你的正则表达式和你的系统可能会崩溃(就像我们的生产系统那样).可以很容易地在Visual Studio中复制,因为我发现它会崩溃.一个简单的try/catch也不会陷入这个问题.
你应该使用:
(?:^|,)(\"(?:[^\"])*\"|[^,]*)
Run Code Online (Sandbox Code Playgroud)
代替
qqb*_*enq 15
我真的很喜欢jimplode的答案,但我认为一个带有yield return的版本更有用,所以这里是:
public IEnumerable<string> SplitCSV(string input)
{
Regex csvSplit = new Regex("(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)", RegexOptions.Compiled);
foreach (Match match in csvSplit.Matches(input))
{
yield return match.Value.TrimStart(',');
}
}
Run Code Online (Sandbox Code Playgroud)
也许让它像扩展方法更有用:
public static class StringHelper
{
public static IEnumerable<string> SplitCSV(this string input)
{
Regex csvSplit = new Regex("(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)", RegexOptions.Compiled);
foreach (Match match in csvSplit.Matches(input))
{
yield return match.Value.TrimStart(',');
}
}
}
Run Code Online (Sandbox Code Playgroud)
这个正则表达式无需循环遍历值和TrimStart(','),就像在接受的答案中一样:
((?<=\")[^\"]*(?=\"(,|$)+)|(?<=,|^)[^,\"]*(?=,|$))
Run Code Online (Sandbox Code Playgroud)
下面是 C# 中的实现:
string values = "111,222,\"33,44,55\",666,\"77,88\",\"99\"";
MatchCollection matches = new Regex("((?<=\")[^\"]*(?=\"(,|$)+)|(?<=,|^)[^,\"]*(?=,|$))").Matches(values);
foreach (var match in matches)
{
Console.WriteLine(match);
}
Run Code Online (Sandbox Code Playgroud)
输出
111
222
33,44,55
666
77,88
99
Run Code Online (Sandbox Code Playgroud)
快速简便:
public static string[] SplitCsv(string line)
{
List<string> result = new List<string>();
StringBuilder currentStr = new StringBuilder("");
bool inQuotes = false;
for (int i = 0; i < line.Length; i++) // For each character
{
if (line[i] == '\"') // Quotes are closing or opening
inQuotes = !inQuotes;
else if (line[i] == ',') // Comma
{
if (!inQuotes) // If not in quotes, end of current string, add it to result
{
result.Add(currentStr.ToString());
currentStr.Clear();
}
else
currentStr.Append(line[i]); // If in quotes, just add it
}
else // Add any other character to current string
currentStr.Append(line[i]);
}
result.Add(currentStr.ToString());
return result.ToArray(); // Return array of all strings
}
Run Code Online (Sandbox Code Playgroud)
使用此字符串作为输入:
111,222,"33,44,55",666,"77,88","99"
Run Code Online (Sandbox Code Playgroud)
它将返回:
111
222
33,44,55
666
77,88
99
Run Code Online (Sandbox Code Playgroud)