Csv को कैसे विभाजित करें जिसके कॉलम में हो सकता है,


105

दिया हुआ

2,1016,7 / 31/2008 14: 22, ज्योफ डेलगास, 6/5/2011 22:21, http://stackoverflow.com , "Corvallis, OR", 7679,351,81, b437f461x3fd27387c5d8ab47a293d35,34,34,34

उपरोक्त जानकारी को निम्न प्रकार से विभाजित करने के लिए C # का उपयोग कैसे करें:

2
1016
7/31/2008 14:22
Geoff Dalgas
6/5/2011 22:21
http://stackoverflow.com
Corvallis, OR
7679
351
81
b437f461b3fd27387c5d8ab47a293d35
34

जैसा कि आप देख सकते हैं कि एक कॉलम में शामिल है, <= (Corvallis, OR)

// अपडेट // सी # रेगेक्स स्प्लिट के आधार पर - उद्धरणों के बाहर अल्पविराम

string[] result = Regex.Split(samplestring, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");

1
हालांकि जावा में, समान प्रश्न: stackoverflow.com/questions/1757065/…
sgokhales

1
ऐसा करने के लिए एक regex का उपयोग करना बुरी सलाह है। .NET फ्रेमवर्क CSV को पार्स करने के लिए पहले से ही अंतर्निहित है। इस उत्तर को देखें जो आपको स्वीकार करना चाहिए। अन्यथा मैं इसे stackoverflow.com/questions/3147836/… के रूप में बंद कर दूंगा जो कि उतना ही गलत है।
केव

आप एम्बेडेड कॉमा के साथ CSV फ़ाइलों को पार्स करने के लिए .NET का इन-बिल्ट सपोर्ट क्या है, इसे विस्तृत कर सकते हैं? क्या आप Microsoft.VisualBasic.FileIO.TextFieldParser वर्ग की बात कर रहे हैं?
ऑल सॉल्यूशंस

जवाबों:


182

Microsoft.VisualBasic.FileIO.TextFieldParserकक्षा का उपयोग करें । यह एक सीमांकित फ़ाइल को पार्स करने में सक्षम होगा, TextReaderया Streamजहां कुछ फ़ील्ड उद्धरणों में संलग्न हैं और कुछ नहीं हैं।

उदाहरण के लिए:

using Microsoft.VisualBasic.FileIO;

string csv = "2,1016,7/31/2008 14:22,Geoff Dalgas,6/5/2011 22:21,http://stackoverflow.com,\"Corvallis, OR\",7679,351,81,b437f461b3fd27387c5d8ab47a293d35,34";

TextFieldParser parser = new TextFieldParser(new StringReader(csv));

// You can also read from a file
// TextFieldParser parser = new TextFieldParser("mycsvfile.csv");

parser.HasFieldsEnclosedInQuotes = true;
parser.SetDelimiters(",");

string[] fields;

while (!parser.EndOfData)
{
    fields = parser.ReadFields();
    foreach (string field in fields)
    {
        Console.WriteLine(field);
    }
} 

parser.Close();

इसका परिणाम निम्न आउटपुट में होना चाहिए:

2
1016
7/31/2008 14:22
ज्योफ डेलगास
6/5/2011 22:21
http://stackoverflow.com
कोरवालिस, या
7679
351
81
b437f461b3fd27387c5d8ab47a293d35
34

अधिक जानकारी के लिए Microsoft.VisualBasic.FileIO.TextFieldParser देखें ।

आपको संदर्भ Microsoft.VisualBasicजोड़ें .NET टैब में एक संदर्भ जोड़ने की आवश्यकता है ।


9
यार, इस समाधान के लिए बहुत बहुत धन्यवाद, मेरे पास लगभग 500K + CSV डेटा की पंक्तियाँ हैं जिन्हें मुझे एक तालिका में लोड करने की आवश्यकता है और यह उद्धरणों के अंदर समाहित कॉमा से भरी हुई है। यदि आपकी राहें कभी भी पार हो जाती हैं, तो मैं आपको आपकी पसंद का वयस्क पेय देता हूँ।
मार्क क्रैम

@tim मैंने इसका उपयोग किया है, और इसके सभी लाइन नंबरों को छोड़ दिया है, केवल विषम लाइन नंबरों को एक फ़ाइल में संसाधित किया है जिसमें 1050 लाइनें हैं। कोई विचार?
स्मिथ

@ स्मिथ - आपके कोड या नमूना इनपुट को देखे बिना मुझे कोई पता नहीं है। मैं एक नया प्रश्न पोस्ट करने का सुझाव देता हूं। हो सकता है कि फ़ाइल में भी तर्ज पर एक गाड़ी वापसी या अन्य अंत-पंक्ति मार्कर गायब हो?
टिम

मुझे इस लाइब्रेरी के बारे में तब तक पता नहीं चला जब तक मैंने इसे नहीं देखा - धन्यवाद! यदि कोई और एक उदाहरण चाहता है जो पूरी CSV फ़ाइल को पार्स करता है, तो इस SO उत्तर को देखें: stackoverflow.com/a/3508572/3105807
एमी बैरेट

2
क्या हम माइक्रोसॉफ्ट को एक कंस्ट्रक्टर प्रदान करने के लिए नहीं दे सकते हैं जो एक स्ट्रिंग प्रदान करता है इसलिए हमें इसे पहले एक धारा में परिवर्तित करने के घेरा से कूदना होगा ?? अन्यथा, अच्छा जवाब।
लोरेन Pechtel

43

इतनी देर हो चुकी है लेकिन यह किसी के लिए मददगार हो सकता है। हम RegEx को bellow के रूप में उपयोग कर सकते हैं।

Regex CSVParser = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
String[] Fields = CSVParser.Split(Test);

4
यह पूर्ण है। बल्कि एक पूरे अन्य पुस्तकालय आयात से यह प्रयोग करेंगे। वाहवाही।
द गीक यू नीड

1
Asdf से,

यह समाधान सही तरीके से काम नहीं करता है - यह भाषण के निशान के लिए खाता नहीं है, जिसका अर्थ है कि पढ़ने के दौरान गलत स्थानों में बहुत सारे भाषण के निशान होंगे।
अयोधन

यदि समाप्त होने वाली बोली कुछ पंक्ति में याद आ रही है: asd, "", "as, \" df "," asd asd "," as
MarmiK

1
इसने मेरे लिए काम किया और उद्धरण चिह्नों के लिए जिम्मेदार था। उनकी 30 मिलियन पंक्तियाँ। बहुत अच्छी और न्यूनतम मात्रा का कोड।
GBGOLC

4

आप उन सभी कॉमाओं पर विभाजित हो सकते हैं जिनके पास उद्धरणों की एक समान संख्या है।

आप specfकॉमा से निपटने के बारे में सीएसवी प्रारूप के लिए भी देखना चाहेंगे ।

उपयोगी लिंक: C# Regex Split - commas outside quotes


3
@ q0987 - यह सही उत्तर नहीं है। फ्रेमवर्क में इसके समर्थन में बनाया गया है: stackoverflow.com/questions/6542996/…
Kev

4

मैं देखता हूं कि यदि आप एक्सेल में सीएसएस सीमांकित पाठ पेस्ट करते हैं और "टेक्स्ट टू कॉलम" करते हैं, तो यह आपसे "टेक्स्ट क्वालिफायर" के लिए पूछता है। यह एक दोहरे उद्धरण के लिए डिफ़ॉल्ट है ताकि यह शाब्दिक के रूप में दोहरे उद्धरणों के भीतर पाठ का इलाज करे। मुझे लगता है कि एक्सेल एक बार में एक चरित्र पर जाकर इसे लागू करता है, अगर यह एक "टेक्स्ट क्वालिफायर" का सामना करता है, तो यह अगले "क्वालिफायर" पर जाता है। यदि आप शाब्दिक पाठ के अंदर हैं, तो आप संभवतः इसे लूप और बूलियन के साथ लागू कर सकते हैं।

public string[] CsvParser(string csvText)
{
    List<string> tokens = new List<string>();

    int last = -1;
    int current = 0;
    bool inText = false;

    while(current < csvText.Length)
    {
        switch(csvText[current])
        {
            case '"':
                inText = !inText; break;
            case ',':
                if (!inText) 
                {
                    tokens.Add(csvText.Substring(last + 1, (current - last)).Trim(' ', ',')); 
                    last = current;
                }
                break;
            default:
                break;
        }
        current++;
    }

    if (last != csvText.Length - 1) 
    {
        tokens.Add(csvText.Substring(last+1).Trim());
    }

    return tokens.ToArray();
}

3

अपनी CSV रीडिंग करने के लिए LumenWorks जैसी लाइब्रेरी का उपयोग करें । यह उनमें उद्धरणों के साथ फ़ील्ड्स को हैंडल करेगा और संभवत: आपके कस्टम समाधान की तुलना में अधिक मजबूत होगा जो कि लंबे समय से आसपास रहा है।


2

.Csv फ़ाइलों को पार्स करने के लिए यह एक पेचीदा मामला है। जब .csv फ़ाइल कोमा से अलग तार, अल्पविराम से अलग किए गए तार, या दोनों के अराजक संयोजन हो सकते हैं। समाधान मैं तीन संभावनाओं में से किसी के लिए अनुमति देता है के साथ आया था।

मैंने एक विधि बनाई, ParseCsvRow () जो एक csv स्ट्रिंग से एक सरणी देता है। मैं पहले स्ट्रिंग में डबल कोट्स को एक सरणी में डबल कोट्स में विभाजित करके स्ट्रिंग उद्धरण में डबल डील करता हूं। उद्धृत स्ट्रिंग .csv फ़ाइलें केवल तभी मान्य होती हैं यदि दोहरे उद्धरण चिह्नों की संख्या हो। एक स्तंभ मान में डबल उद्धरण को दोहरे उद्धरणों की जोड़ी के साथ प्रतिस्थापित किया जाना चाहिए (यह एक्सेल का दृष्टिकोण है)। जब तक .csv फ़ाइल इन आवश्यकताओं को पूरा करती है, आप सीमांकक अल्पविराम को केवल दोहरे उद्धरण चिह्नों के बाहर प्रदर्शित करने की अपेक्षा कर सकते हैं। दोहरे उद्धरण चिह्नों के जोड़े के अंदर कामास स्तंभ मान का हिस्सा है और .csv को एक सरणी में विभाजित करते समय इसे अनदेखा किया जाना चाहिए।

मेरा तरीका दोहरे उद्धरण जोड़े के बाहर अल्पविराम के लिए परीक्षण करेगा यहां तक ​​कि केवल उद्धरण के अनुक्रमों को देखकर। यह स्तंभ मानों के प्रारंभ और अंत से दोहरे उद्धरण भी निकालता है।

    public static string[] ParseCsvRow(string csvrow)
    {
        const string obscureCharacter = "ᖳ";
        if (csvrow.Contains(obscureCharacter)) throw new Exception("Error: csv row may not contain the " + obscureCharacter + " character");

        var unicodeSeparatedString = "";

        var quotesArray = csvrow.Split('"');  // Split string on double quote character
        if (quotesArray.Length > 1)
        {
            for (var i = 0; i < quotesArray.Length; i++)
            {
                // CSV must use double quotes to represent a quote inside a quoted cell
                // Quotes must be paired up
                // Test if a comma lays outside a pair of quotes.  If so, replace the comma with an obscure unicode character
                if (Math.Round(Math.Round((decimal) i/2)*2) == i)
                {
                    var s = quotesArray[i].Trim();
                    switch (s)
                    {
                        case ",":
                            quotesArray[i] = obscureCharacter;  // Change quoted comma seperated string to quoted "obscure character" seperated string
                            break;
                    }
                }
                // Build string and Replace quotes where quotes were expected.
                unicodeSeparatedString += (i > 0 ? "\"" : "") + quotesArray[i].Trim();
            }
        }
        else
        {
            // String does not have any pairs of double quotes.  It should be safe to just replace the commas with the obscure character
            unicodeSeparatedString = csvrow.Replace(",", obscureCharacter);
        }

        var csvRowArray = unicodeSeparatedString.Split(obscureCharacter[0]); 

        for (var i = 0; i < csvRowArray.Length; i++)
        {
            var s = csvRowArray[i].Trim();
            if (s.StartsWith("\"") && s.EndsWith("\""))
            {
                csvRowArray[i] = s.Length > 2 ? s.Substring(1, s.Length - 2) : "";  // Remove start and end quotes.
            }
        }

        return csvRowArray;
    }

मेरे दृष्टिकोण में से एक नकारात्मक तरीका यह है कि मैं अस्थायी रूप से सीमांत अल्पविराम को एक अस्पष्ट यूनिकोड चरित्र के साथ बदल देता हूं। इस चरित्र को इतना अस्पष्ट होना चाहिए, यह आपकी .csv फ़ाइल में कभी नहीं दिखाई देगा। आप इसके आस-पास अधिक हैंडलिंग रख सकते हैं।


1

मुझे CSV के साथ एक समस्या थी जिसमें उनमें एक बोली चरित्र वाले फ़ील्ड शामिल हैं, इसलिए TextFieldParser का उपयोग करते हुए, मैं निम्नलिखित के साथ आया:

private static string[] parseCSVLine(string csvLine)
{
  using (TextFieldParser TFP = new TextFieldParser(new MemoryStream(Encoding.UTF8.GetBytes(csvLine))))
  {
    TFP.HasFieldsEnclosedInQuotes = true;
    TFP.SetDelimiters(",");

    try 
    {           
      return TFP.ReadFields();
    }
    catch (MalformedLineException)
    {
      StringBuilder m_sbLine = new StringBuilder();

      for (int i = 0; i < TFP.ErrorLine.Length; i++)
      {
        if (i > 0 && TFP.ErrorLine[i]== '"' &&(TFP.ErrorLine[i + 1] != ',' && TFP.ErrorLine[i - 1] != ','))
          m_sbLine.Append("\"\"");
        else
          m_sbLine.Append(TFP.ErrorLine[i]);
      }

      return parseCSVLine(m_sbLine.ToString());
    }
  }
}

एक StreamReader का उपयोग अभी भी लाइन द्वारा CSV लाइन को पढ़ने के लिए किया जाता है:

using(StreamReader SR = new StreamReader(FileName))
{
  while (SR.Peek() >-1)
    myStringArray = parseCSVLine(SR.ReadLine());
}

1

साथ Cinchoo ईटीएल - एक खुला स्रोत पुस्तकालय, यह स्वचालित रूप से हैंडल कॉलम मूल्यों विभाजक युक्त कर सकते हैं।

string csv = @"2,1016,7/31/2008 14:22,Geoff Dalgas,6/5/2011 22:21,http://stackoverflow.com,""Corvallis, OR"",7679,351,81,b437f461b3fd27387c5d8ab47a293d35,34";

using (var p = ChoCSVReader.LoadText(csv)
    )
{
    Console.WriteLine(p.Dump());
}

आउटपुट:

Key: Column1 [Type: String]
Value: 2
Key: Column2 [Type: String]
Value: 1016
Key: Column3 [Type: String]
Value: 7/31/2008 14:22
Key: Column4 [Type: String]
Value: Geoff Dalgas
Key: Column5 [Type: String]
Value: 6/5/2011 22:21
Key: Column6 [Type: String]
Value: http://stackoverflow.com
Key: Column7 [Type: String]
Value: Corvallis, OR
Key: Column8 [Type: String]
Value: 7679
Key: Column9 [Type: String]
Value: 351
Key: Column10 [Type: String]
Value: 81
Key: Column11 [Type: String]
Value: b437f461b3fd27387c5d8ab47a293d35
Key: Column12 [Type: String]
Value: 34

अधिक जानकारी के लिए, कृपया कोडप्रोजेक्ट लेख देखें।

आशा करता हूँ की ये काम करेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.