[英]Parse comma seperated string with a complication in C#
我知道如何從逗號分隔的字符串中獲取子字符串,但這是一個復雜問題:如果子字符串包含逗號,該怎么辦。
如果子字符串包含逗號,換行符或雙引號,則整個子字符串將用雙引號封裝。
如果子字符串包含雙引號,則雙引號將被另一個雙引號轉義。 最糟糕的情況是如果我有這樣的事情:
first,"second, second","""third"" third","""fourth"", fourth"
在這種情況下,子字符串為:
第二,第二個是用雙引號封裝的,我不想在列表/數組中使用那些雙引號。
“第三”三分之一用雙引號封裝,因為它包含雙引號,而那些用附加雙引號轉義。 同樣,我不希望將雙引號封裝在列表/數組中,也不希望使用雙引號來轉義雙引號,但是我希望原始雙引號是子字符串的一部分。
一種使用TextFieldParser
:
using (var reader = new StringReader("first,\"second, second\",\"\"\"third\"\" third\",\"\"\"fourth\"\", fourth\""))
using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(reader))
{
parser.Delimiters = new[] { "," };
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData)
{
foreach (var field in parser.ReadFields())
Console.WriteLine(field);
}
}
對於
first
second, second
"third" third
"fourth", fourth
嘗試這個
string input = "first,\\"second, second\\",\\"\\"\\"third\\"\\" third\\",\\"\\"\\"fourth\\"\\", fourth\\""; string[] output = input.Split(new string[] {"\\",\\""}, StringSplitOptions.RemoveEmptyEntries);
我建議您為此問題構造一個小型狀態機。 您將具有以下狀態:
這肯定會正確讀取CSV。 您還可以使分隔符可配置,以便支持TSV或分號分隔的格式。
另外請記住CSV格式的一個非常重要的情況:引用的字段可能包含換行! 另一個需要注意的特殊情況:空字段(例如:、、)。
這不是最優雅的解決方案,但可能會對您有所幫助。 我會遍歷字符並對引號進行奇偶計數。 例如,如果遇到引號奇數,則布爾值為true;對於偶數引號,布爾值為false。
當此布爾值為true時遇到的任何逗號都不應視為分隔符。 如果您知道它是分隔符,則可以使用該信息執行幾項操作。 下面,我用更易於管理的分隔符代替了分隔符(盡管效率不高):
bool odd = false;
char replacementDelimiter = "|"; // Or some very unlikely character
for(int i = 0; i < str.len; ++i)
{
if(str[i] == '\"')
odd = !odd;
else if (str[i] == ',')
{
if(!odd)
str[i] = replacementDelimiter;
}
}
string[] commaSeparatedTokens = str.Split(replacementDelimiter);
此時,您應該有一個字符串數組,這些字符串在您想要的逗號之間分開。 從這里開始,將更容易處理報價。
希望對您有所幫助。
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApp
{
class Program
{
private static IEnumerable<string> Parse(string input)
{
if (string.IsNullOrWhiteSpace(input))
{
// empty string => nothing to do
yield break;
}
int count = input.Length;
StringBuilder sb = new StringBuilder();
int j;
for (int i = 0; i < count; i++)
{
char c = input[i];
if (c == ',')
{
yield return sb.ToString();
sb.Clear();
}
else if (c == '"')
{
// begin quoted string
sb.Clear();
for (j = i + 1; j < count; j++)
{
if (input[j] == '"')
{
// quote
if (j < count - 1 && input[j + 1] == '"')
{
// double quote
sb.Append('"');
j++;
}
else
{
break;
}
}
else
{
sb.Append(input[j]);
}
}
yield return sb.ToString();
// clear buffer and skip to next comma
sb.Clear();
for (i = j + 1; i < count && input[i] != ','; i++) ;
}
else
{
sb.Append(c);
}
}
}
[STAThread]
static void Main(string[] args)
{
foreach (string str in Parse("first,\"second, second\",\"\"\"third\"\" third\",\"\"\"fourth\"\", fourth\""))
{
Console.WriteLine(str);
}
Console.WriteLine();
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
謝謝您的回答,但是在我看到它們之前,我寫了這個解決方案,它雖然不漂亮,但對我有用。
string line = "first,\"second, second\",\"\"\"third\"\" third\",\"\"\"fourth\"\", fourth\"";
var substringArray = new List<string>();
string substring = null;
var doubleQuotesCount = 0;
for (var i = 0; i < line.Length; i++)
{
if (line[i] == ',' && (doubleQuotesCount % 2) == 0)
{
substringArray.Add(substring);
substring = null;
doubleQuotesCount = 0;
continue;
}
else
{
if (line[i] == '"')
doubleQuotesCount++;
substring += line[i];
//If it is a last character
if (i == line.Length - 1)
{
substringArray.Add(substring);
substring = null;
doubleQuotesCount = 0;
}
}
}
for(var i = 0; i < substringArray.Count; i++)
{
if (substringArray[i] != null)
{
//remove first double quote
if (substringArray[i][0] == '"')
{
substringArray[i] = substringArray[i].Substring(1);
}
//remove last double quote
if (substringArray[i][substringArray[i].Length - 1] == '"')
{
substringArray[i] = substringArray[i].Remove(substringArray[i].Length - 1);
}
//Replace double double quotes with single double quote
substringArray[i] = substringArray[i].Replace("\"\"", "\"");
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.