簡體   English   中英

在C#中使用逗號解析逗號分隔的字符串

[英]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); 

我建議您為此問題構造一個小型狀態機。 您將具有以下狀態:

  • 外出-在到達第一個字段之前
  • InQuoted-您已離開並到達;現在您已進入並引用了該字段
  • InQuotedMaybeOut-您已被InQuoted並“到達”;現在您等待下一個字符確定是另一個字符還是其他字符; 如果不是,則選擇下一個有效狀態(字符可以是空格,換行,逗號,以便您確定下一個狀態); 否則,如果“到達,則將”推送到輸出並返回到InQuoted
  • 由內至外,當除和之外的任何字符到達時,您將自動進入未引用的新字段。

這肯定會正確讀取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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM