разобрать текстовый файл и удалить запятые внутри двойных кавычек

У меня есть текстовый файл, который нужно преобразовать в файл csv. Мой план состоит в том, чтобы:

  • разобрать файл построчно
  • искать и заменять запятые внутри двойных кавычек пробелом
  • затем удалите все двойные кавычки
  • добавить строку в новый файл csv

Вопрос: Мне нужна функция, которая будет распознавать запятую внутри двойной кавычки и заменять ее.

Вот пример строки:

"МИССИС Браун", "4611 BEAUMONT ST", ","WARRIOR RUN, PA"


person Internet Engineer    schedule 27.03.2012    source источник
comment
Могут ли быть кавычки внутри строк в кавычках? Если да, то как они будут спасаться? (Например, "quotes \"inside\" other quotes" или "quotes ""inside"" other quotes"?)   -  person Aasmund Eldhuset    schedule 27.03.2012
comment
Да, внутри двойных кавычек могут быть кавычки.   -  person Internet Engineer    schedule 27.03.2012
comment
Я пробовал выражения регулярных выражений и замену.   -  person Internet Engineer    schedule 27.03.2012
comment
.NET имеет хорошую поддержку для этого, используйте класс TextFieldParser. Это дает вам строку [], затем вы можете просто использовать string.Replace, чтобы разбить запятые.   -  person Hans Passant    schedule 27.03.2012


Ответы (8)


Похоже, ваш файл уже находится в формате жалобы CSV. Любой хороший читатель CSV сможет прочитать его правильно.

Если ваша проблема заключается в правильном чтении значений полей, то вам нужно читать их правильно.

Вот один из способов сделать это:

using Microsoft.VisualBasic.FileIO; 


    private void button1_Click(object sender, EventArgs e)
    {
        TextFieldParser tfp = new TextFieldParser("C:\\Temp\\Test.csv");
        tfp.Delimiters = new string[] { "," };
        tfp.HasFieldsEnclosedInQuotes = true;
        while (!tfp.EndOfData)
        {
            string[] fields = tfp.ReadFields();

            // do whatever you want to do with the fields now...
            // e.g. remove the commas and double-quotes from the fields.
            for (int i = 0; i < fields.Length;i++ )
            {
                fields[i] = fields[i].Replace(","," ").Replace("\"","");
            }

            // this is to show what we got as the output
            textBox1.AppendText(String.Join("\t", fields) + "\n");
        }
        tfp.Close();
    }

ИЗМЕНИТЬ:

Я только что заметил, что вопрос был подан под C #, VB.NET-2010. Вот версия VB.NET, на всякий случай, если вы кодируете в VB.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim tfp As New FileIO.TextFieldParser("C:\Temp\Test.csv")
    tfp.Delimiters = New String() {","}
    tfp.HasFieldsEnclosedInQuotes = True
    While Not tfp.EndOfData
        Dim fields() As String = tfp.ReadFields

        '' do whatever you want to do with the fields now...
        '' e.g. remove the commas and double-quotes from the fields.
        For i As Integer = 0 To fields.Length - 1
            fields(i) = fields(i).Replace(",", " ").Replace("""", "")
        Next
        '' this is to show what we got as the output
        TextBox1.AppendText(Join(fields, vbTab) & vbCrLf)
    End While
    tfp.Close()
End Sub
person Pradeep Kumar    schedule 27.03.2012

Вот простая функция, которая удалит запятые между двумя двойными кавычками в строке. Вы можете передать длинную строку, которая имеет несколько вхождений «abc, 123», 10/13/12, «какое-то описание» и т. д. Это также удалит двойные кавычки.

Private Function ParseCommasInQuotes(ByVal arg As String) As String

    Dim foundEndQuote As Boolean = False
    Dim foundStartQuote As Boolean = False
    Dim output As New StringBuilder()

    '44 = comma
    '34 = double quote

    For Each element As Char In arg

        If foundEndQuote Then
            foundStartQuote = False
            foundEndQuote = False
        End If

        If element.Equals(Chr(34)) And (Not foundEndQuote) And foundStartQuote Then
            foundEndQuote = True
            Continue For
        End If


        If element.Equals(Chr(34)) And Not foundStartQuote Then
            foundStartQuote = True
            Continue For
        End If


        If (element.Equals(Chr(44)) And foundStartQuote) Then
            'skip the comma...its between double quotes
        Else
            output.Append(element)
        End If

    Next

    Return output.ToString()

End Function
person The Glockster    schedule 05.11.2012

Благодаря Baz, The Glockster Answer в VB, я только что преобразовал его в C#, и он работает хорошо. С этим кодом вам не нужен сторонний парсер.

string line = reader.ReadLine();                    
line = ParseCommasInQuotes(line);

private string ParseCommasInQuotes(string arg)
{

  bool foundEndQuote = false;
  bool foundStartQuote = false;
  StringBuilder output = new StringBuilder();

  //44 = comma
  //34 = double quote

  foreach (char element in arg)
  {
    if (foundEndQuote)
    {
      foundStartQuote = false;
      foundEndQuote = false;
    }

    if (element.Equals((Char)34) & (!foundEndQuote) & foundStartQuote)
    {
      foundEndQuote = true;
      continue;
    }

    if (element.Equals((Char)34) & !foundStartQuote)
    {
      foundStartQuote = true;
      continue;
    }

    if ((element.Equals((Char)44) & foundStartQuote))
    {
      //skip the comma...its between double quotes
    }
    else
    {
      output.Append(element);
    }
  }
  return output.ToString();
}
person Hasan Abrar    schedule 23.07.2014

Я не понял вашего вопроса раньше. Теперь я уверен, что правильно понял:

TextFieldParser parser = new TextFieldParser(@"c:\file.csv");
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while (!parser.EndOfData) 
{
    //Processing row
    string[] fields = parser.ReadFields();
    foreach (string field in fields) 
    {
        //TODO: Do whatever you need
    }
}
parser.Close();
person Michal B.    schedule 27.03.2012
comment
Вопрос только в том, как убрать запятую внутри двойных кавычек - person Internet Engineer; 27.03.2012

Не похоже, что то, что вы описываете, в конечном итоге станет CSV-файлом, но, чтобы ответить на ваш вопрос, я бы сделал это.

Сначала вам нужно превратить текстовый файл в какой-нибудь пригодный для использования код, который можно зациклить следующим образом:

    public static List<String> GetTextListFromDiskFile(String fileName)
    {
        List<String> list = new List<String>();
        try
        {
            //load the file into the streamreader 
            System.IO.StreamReader sr = new System.IO.StreamReader(fileName);

            //loop through each line of the file
            while (sr.Peek() >= 0)
            {
                list.Add(sr.ReadLine());
            }
            sr.Close();
        }
        catch (Exception ex)
        {
            list.Add("Error: Could not read file from disk. Original error: " + ex.Message);
        }

        return list;
    }

Затем прокрутите список и, используя простой цикл foreach, запустите замену в списке следующим образом:

        foreach (String item in list)
        {
            String x = item.Replace("\",\"", "\" \"");
            x = x.Replace("\"", "");
        }

После этого вам нужно создать CSV-файл построчно. Я бы снова использовал StringBuilder, а затем просто выполнил sb.AppendLine(x), чтобы создать строку, которая станет текстовым файлом, а затем записать ее на диск, используя что-то вроде этого.

    public static void SaveFileToDisk(String filePathName, String fileText)
    {
        using (StreamWriter outfile = new StreamWriter(filePathName))
        {
            outfile.Write(fileText);
        }
    }
person RJ.    schedule 27.03.2012
comment
извините, но это заменит запятую между двойными кавычками, а не запятую внутри двойных кавычек -> WARRIOR RUN, PA - person Steve; 27.03.2012

Это сработало для меня. Надеюсь, это поможет кому-то еще.

Private Sub Command1_Click()
Open "c:\\dir\file.csv" For Input As #1
Open "c:\\dir\file2.csv" For Output As #2
Do Until EOF(1)
Line Input #1, test$
99
c = InStr(test$, """""")
If c > 0 Then
test$ = Left$(test$, c - 1) + Right$(test$, Len(test$) - (c + 1))
GoTo 99
End If
Print #2, test$
Loop
End Sub
person andy    schedule 15.02.2015

Я бы сделал все это до того, как вы начнете обрабатывать его построчно. Также проверьте CsvHelper. Это быстро и легко. Просто возьмите свои результаты и поместите их в TextReader, а затем передайте в CvsReader.

Вот ваша запятая (в двойных кавычках), а затем последующий разделитель двойных кавычек.

        using (TextReader reader = File.OpenText(file))
        {
            // remove commas and double quotes inside file
            var pattern = @"\""(.+?,.+)+\""";
            var results = Regex.Replace(reader.ReadToEnd(), pattern, match => match.Value.Replace(",", " "));
            results = results.Replace("\"", "");
         }
person Phillip Brandon Holmes    schedule 06.03.2019

person    schedule
comment
В моем коде это просто удаляет запятые, даже если они выходят за двойные кавычки. - person Christian Findlay; 09.04.2020