csv सूचक - एक सीएसवी फ़ाइल में अल्पविराम से निपटना





चिह्न लोप (18)


फ़ील्ड को अलग करने के लिए एक टैब वर्ण (\ t) का उपयोग करें।

मैं एक सीएसवी फ़ाइल को कैसे संभालना है, उसके बारे में सुझावों की तलाश कर रहा हूं, फिर हमारे ग्राहकों द्वारा अपलोड किया गया है, और उसमें कंपनी के नाम की तरह मूल्य में कॉमा हो सकता है।

हम जिन विचारों को देख रहे हैं उनमें से कुछ हैं: उद्धृत पहचानकर्ता (मूल्य "," मान "," आदि) या एक का उपयोग कर | एक अल्पविराम के बजाय। सबसे बड़ी समस्या यह है कि हमें इसे आसान बनाना है, या ग्राहक इसे नहीं करेगा।




2017 के लिए, सीएसवी पूरी तरह से निर्दिष्ट है - आरएफसी 4180।

यह एक बहुत ही सामान्य विनिर्देश है, और पूरी तरह से कई पुस्तकालयों ( github.com/Flinesoft/CSVImporter ) द्वारा कवर किया गया है।

बस किसी भी आसानी से उपलब्ध सीएसवी लाइब्रेरी का उपयोग करें - जो आरएफसी 4180 कहना है।

वास्तव में सीएसवी प्रारूप और कॉमा को संभालने के लिए एक कल्पना है:

लाइन ब्रेक (सीआरएलएफ), डबल कोट्स और कॉमा युक्त फ़ील्ड डबल-कोट्स में संलग्न किए जाने चाहिए।

http://tools.ietf.org/html/rfc4180

तो, मूल्य foo और bar,baz , आप यह करते हैं:

foo,"bar,baz"

विचार करने के लिए एक और महत्वपूर्ण आवश्यकता (spec से भी):

यदि फ़ील्ड को घेरने के लिए डबल-कोट्स का उपयोग किया जाता है, तो किसी फ़ील्ड के अंदर दिखाई देने वाला डबल-कोट एक और डबल कोट के साथ इसे से बचकर अवगत होना चाहिए। उदाहरण के लिए:

"aaa","b""bb","ccc"



आप खेतों के चारों ओर डबल कोट्स डाल सकते हैं। मुझे इस दृष्टिकोण को पसंद नहीं है, क्योंकि यह एक और विशेष चरित्र (डबल कोट) जोड़ता है। बस एक बच निकलने वाले चरित्र (आमतौर पर बैकस्लैश) को परिभाषित करें और जहां भी आपको कुछ बचने की आवश्यकता हो, इसका उपयोग करें:

data,more data,more data\, even,yet more

आपको उद्धरण मिलान करने की कोशिश करने की आवश्यकता नहीं है, और आपके पास पार्स के लिए कम अपवाद हैं। यह आपके कोड को भी सरल बनाता है।




आप वैकल्पिक "delimiters" जैसे ";" का उपयोग कर सकते हैं या "|" लेकिन सबसे सरल शायद उद्धरण हो सकता है जो अधिकांश (सभ्य) सीएसवी पुस्तकालयों और सबसे सभ्य स्प्रैडशीट्स द्वारा समर्थित है।

सीएसवी डिलीमीटर पर अधिक जानकारी और डिलीमीटर का वर्णन करने और उद्धरण देने के लिए मानक प्रारूप के लिए एक नमूना इस वेबपृष्ठ को देखने के लिए




चूंकि यह सामान्य प्रथाओं के बारे में है, हम अंगूठे के नियमों से शुरू करते हैं:

  1. CSV का उपयोग न करें, इसके बजाय xml फ़ाइल को पढ़ने और लिखने के लिए लाइब्रेरी के साथ एक्सएमएल का उपयोग करें।

  2. यदि आपको सीएसवी का उपयोग करना चाहिए। इसे ठीक से करें और CSV फ़ाइलों को पार्स और स्टोर करने के लिए एक मुफ्त लाइब्रेरी का उपयोग करें।

औचित्य साबित करने के लिए 1), अधिकांश सीएसवी पार्सर एन्कोडिंग एन्कोडिंग नहीं कर रहे हैं, इसलिए यदि आप यूएस-एएससीआईआई से निपट नहीं रहे हैं तो आप परेशानियों के लिए पूछ रहे हैं। उदाहरण के लिए एक्सेलिंग के बारे में किसी भी नोट के बिना एक्सेल 2002 स्थानीय एन्कोडिंग में सीएसवी संग्रहीत कर रहा है। सीएसवी मानक व्यापक रूप से अपनाया नहीं जाता है :( दूसरी तरफ एक्सएमएल मानक अच्छी तरह से अपनाया जाता है और यह एन्कोडिंग को अच्छी तरह से संभालता है।

औचित्य साबित करने के लिए 2), लगभग सभी भाषाओं के लिए सीएसवी पार्सर्स के आस-पास बहुत सारे हैं इसलिए समाधान को बहुत सरल दिखने के बावजूद पहिया को फिर से शुरू करने की कोई आवश्यकता नहीं है।

कुछ नाम देने के लिए:

  • पाइथन उपयोग के लिए csv मॉड्यूल में निर्माण

  • पर्ल चेक सीपीएएन और Text::CSV

  • PHP उपयोग के लिए fgetcsv / fputcsv कार्यों में निर्माण के लिए

  • जावा चेक SuperCVS पुस्तकालय के लिए

वास्तव में इसे हाथ से लागू करने की कोई आवश्यकता नहीं है यदि आप इसे एम्बेडेड डिवाइस पर पार्स नहीं कर रहे हैं।




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

आलेख सी # का उपयोग करता है और कोड डाउनलोड करने के लिए नीचे एक लिंक है।




सबसे पहले, आइए खुद से पूछें, "हमें सीएसवी फाइलों के लिए अलग-अलग कॉमा को संभालने की आवश्यकता क्यों महसूस होती है?"

मेरे लिए, जवाब है, "क्योंकि जब मैं एक CSV फ़ाइल में डेटा निर्यात करता हूं, तो एक फ़ील्ड में कॉमा गायब हो जाते हैं और मेरा फ़ील्ड कई फ़ील्ड में अलग हो जाता है जहां अल्पविराम मूल डेटा में दिखाई देता है।" (ऐसा इसलिए है क्योंकि अल्पविराम सीएसवी क्षेत्र विभाजक चरित्र है।)

आपकी स्थिति के आधार पर, अर्ध कोलन का उपयोग सीएसवी फील्ड विभाजक के रूप में भी किया जा सकता है।

मेरी आवश्यकताओं को देखते हुए, मैं एक चरित्र का उपयोग कर सकता हूं, उदाहरण के लिए, एकल कम-9 उद्धरण चिह्न, जो अल्पविराम की तरह दिखता है।

तो, यहां यह है कि आप इसे कैसे कर सकते हैं:

// Replace special CSV characters with single low-9 quotation mark
func Scrub(a interface{}) string {
    s := fmt.Sprint(a)
    s = strings.Replace(s, ",", "‚", -1)
    s = strings.Replace(s, ";", "‚", -1)
    return s
}

प्रतिस्थापन फ़ंक्शन में दूसरा कॉमा दिखने वाला वर्ण दशमलव 8218 है।

ध्यान रखें कि यदि आपके पास ऐसे ग्राहक हैं जिनके पास असीसी-पाठ पाठक हो सकते हैं कि यह decima 8218 वर्ण अल्पविराम की तरह नहीं दिखेगा। यदि यह आपका मामला है, तो मैं आरएफसी 4128 प्रति डबल कोट्स के साथ अल्पविराम (या अर्धविराम) के साथ क्षेत्र के आसपास की सिफारिश करता हूं: https://tools.ietf.org/html/rfc4180




किसी भी अच्छी तरह से बनाए गए सीएसवी (.net) - CsvHelper निपटने के लिए न्यूजेट के माध्यम से एक लाइब्रेरी उपलब्ध है

कक्षा में मानचित्र करने के लिए उदाहरण:

var csv = new CsvReader( textReader );
var records = csv.GetRecords<MyClass>();

व्यक्तिगत फ़ील्ड पढ़ने के लिए उदाहरण:

var csv = new CsvReader( textReader );
while( csv.Read() )
{
    var intField = csv.GetField<int>( 0 );
    var stringField = csv.GetField<string>( 1 );
    var boolField = csv.GetField<bool>( "HeaderName" );
}

क्लाइंट को फ़ाइल प्रारूप को चलाने दें:
, मानक फ़ील्ड डेलीमीटर है, " मानक मान है जो फ़ील्ड से बचने के लिए उपयोग किया जाता है जिसमें एक डिलीमीटर, उद्धरण या रेखा समाप्त होती है।

खेतों के लिए (उदाहरण के लिए) # उपयोग करने के लिए और ' भागने के लिए:

var csv = new CsvReader( textReader );
csv.Configuration.Delimiter = "#";
csv.Configuration.Quote = ''';
// read the file however meets your needs

अधिक दस्तावेज़ीकरण




मुझे लगता है कि इस समस्या का सबसे आसान समाधान ग्राहक को एक्सेल में सीएसवी खोलने के लिए है, और फिर ctrl + r को सभी अल्पविरामों को बदलने के लिए जो भी पहचानकर्ता आप चाहते हैं। यह ग्राहक के लिए बहुत आसान है और आपकी पसंद के डिलीमीटर को पढ़ने के लिए आपके कोड में केवल एक ही बदलाव की आवश्यकता है।




सीएसवी प्रारूप मूल्यों को अलग करने के लिए अल्पविराम का उपयोग करता है, कैरिज रिटर्न, लाइनफ़ीड्स, कॉमा, या डबल कोट्स वाले मान डबल-कोट्स से घिरे होते हैं। वे मान जिनमें डबल कोट्स शामिल हैं उद्धृत किए गए हैं और प्रत्येक शाब्दिक उद्धरण तुरंत पहले उद्धरण से बच निकला है: उदाहरण के लिए, 3 मान:

test
list, of, items
"go" he said

के रूप में एन्कोड किया जाएगा:

test
"list, of, items"
"""go"" he said"

किसी भी क्षेत्र को उद्धृत किया जा सकता है लेकिन केवल फ़ील्ड जिनमें अल्पविराम, सीआर / एनएल, या उद्धरण शामिल हैं, उद्धृत किए जाने चाहिए

सीएसवी प्रारूप के लिए कोई वास्तविक मानक नहीं है, लेकिन लगभग सभी एप्लिकेशन here दस्तावेज सम्मेलनों का पालन करते here । आरएफसी का उल्लेख कहीं और किया गया है, सीएसवी के लिए मानक नहीं है, यह एमआईएम के भीतर सीएसवी का उपयोग करने के लिए एक आरएफसी है और इसमें कुछ अपरंपरागत और अनावश्यक सीमाएं हैं जो इसे एमआईएम के बाहर बेकार बनाती हैं।

एक गोचाचा कि मैंने देखा है कि कई सीएसवी मॉड्यूल समायोजित नहीं है तथ्य यह है कि एक ही क्षेत्र में कई लाइनों को एन्कोड किया जा सकता है जिसका मतलब है कि आप यह नहीं मान सकते कि प्रत्येक पंक्ति एक अलग रिकॉर्ड है, आपको या तो अपनी नई लाइनों की अनुमति नहीं देनी होगी डेटा या इसे संभालने के लिए तैयार रहें।




यूरोप में हमें इस समस्या से पहले इस समस्या को पहले होना चाहिए। यूरोप में हम दशमलव बिंदु के लिए सभी कॉमा का उपयोग करते हैं। नीचे यह संख्याएं देखें:

| American      | Europe        |
| ------------- | ------------- |
| 0.5           | 0,5           |
| 3.14159265359 | 3,14159265359 |
| 17.54         | 17,54         |
| 175,186.15    | 175.186,15    |

तो सीएसवी फाइलों के लिए अल्पविराम विभाजक का उपयोग करना संभव नहीं है। इस कारण से, यूरोप में सीएसवी फाइलों को अर्धविराम ( ; ) से अलग किया जाता है।

माइक्रोसॉफ्ट एक्सेल जैसे प्रोग्राम अर्धविराम से फाइलें पढ़ सकते हैं और विभाजक से स्विच करना संभव है। आप एक टैब ( \t ) को विभाजक के रूप में भी उपयोग कर सकते हैं। रात्रिभोज उपयोगकर्ता से यह जवाब देखें।




मैं आमतौर पर इसे अपने सीएसवी फाइलों में नियमित रूप से पार्सिंग करता हूं। मान लें कि 'लाइन' वैरिएबल एक सीएसवी फ़ाइल के भीतर एक पंक्ति है और सभी कॉलम के मान डबल कोट्स में संलग्न हैं। नीचे दी गई दो पंक्तियां निष्पादित करने के बाद, आपको 'मान' संग्रह में सीएसवी कॉलम मिलेंगे।

// The below two lines will split the columns as well as trim the DBOULE QUOTES around values but NOT within them
    string trimmedLine = line.Trim(new char[] { '\"' });
    List<string> values = trimmedLine.Split(new string[] { "\",\"" }, StringSplitOptions.None).ToList();



यदि आप एक * निक्स-सिस्टम पर हैं , तो sed तक पहुंच है और केवल आपके सीएसवी के एक विशिष्ट क्षेत्र में एक या अधिक अवांछित कॉमा हो सकते हैं, आप निम्न एक-लाइनर का उपयोग इन्हें " आरएफसी 4180 धारा 2 प्रस्ताव करता है:

sed -r 's/([^,]*,[^,]*,[^,]*,)(.*)(,.*,.*)/\1"\2"\3/' inputfile

किन क्षेत्र पर अवांछित कॉमा (ओं) हो सकता है, इस पर निर्भर करता है कि आपको रेगेक्स (और प्रतिस्थापन) के कैप्चरिंग समूहों को बदलना / विस्तार करना है।
उपरोक्त उदाहरण उद्धरण चिह्नों में चौथे क्षेत्र (छः में से) को घेर लेगा।

इन --in-place-option साथ संयोजन में आप इन परिवर्तनों को सीधे फ़ाइल पर लागू कर सकते हैं।

सही रेगेक्स को "निर्माण" करने के लिए, अनुसरण करने के लिए एक सरल सिद्धांत है:

  1. आपके सीएसवी के हर क्षेत्र के लिए जो अनचाहे कॉमा के साथ मैदान से पहले आता है, आप एक [^,]*, लिखते हैं [^,]*, और उन्हें एक कैप्चरिंग समूह में एक साथ रख देते हैं।
  2. उस फ़ील्ड के लिए जिसमें अवांछित कॉमा (नों) लिखते हैं (.*)
  3. अनचाहे कॉमा (ओं) के साथ मैदान के बाद हर क्षेत्र के लिए आप एक लिखते हैं ,.* और उन्हें एक कैप्चरिंग समूह में एक साथ रख दें।

विशिष्ट फ़ील्ड के आधार पर विभिन्न संभावित रेगेक्स / प्रतिस्थापन का संक्षिप्त अवलोकन यहां दिया गया है। यदि नहीं दिया गया है, प्रतिस्थापन \1"\2"\3

([^,]*)(,.*)                     #first field, regex
"\1"\2                           #first field, substitution

(.*,)([^,]*)                     #last field, regex
\1"\2"                           #last field, substitution


([^,]*,)(.*)(,.*,.*,.*)          #second field (out of five fields)
([^,]*,[^,]*,)(.*)(,.*)          #third field (out of four fields)
([^,]*,[^,]*,[^,]*,)(.*)(,.*,.*) #fourth field (out of six fields)

यदि आप अवांछित कॉमा को उद्धरण चिह्नों के साथ संलग्न करने के बजाय sed साथ हटाना चाहते हैं तो इस उत्तर का संदर्भ लें।




यदि आप पहिया को फिर से शुरू करना चाहते हैं, तो निम्नलिखित आपके लिए काम कर सकता है:

public static IEnumerable<string> SplitCSV(string line)
{
    var s = new StringBuilder();
    bool escaped = false, inQuotes = false;
    foreach (char c in line)
    {
        if (c == ',' && !inQuotes)
        {
            yield return s.ToString();
            s.Clear();
        }
        else if (c == '\\' && !escaped)
        {
            escaped = true;
        }
        else if (c == '"' && !escaped)
        {
            inQuotes = !inQuotes;
        }
        else
        {
            escaped = false;
            s.Append(c);
        }
    }
    yield return s.ToString();
}



मैं आमतौर पर उन क्षेत्रों को यूआरएल-एन्कोड करता हूं जिनमें कोई कॉमा या कोई विशेष वर्ण हो सकता है। और तब इसे किसी भी दृश्य माध्यम में उपयोग / प्रदर्शित होने पर डीकोड करें।

(अल्पविराम% 2 सी बन जाता है)

प्रत्येक भाषा में URL-encode और स्ट्रिंग को डीकोड करने के तरीके हो सकते हैं।

उदाहरण के लिए, जावा में

URLEncoder.encode(myString,"UTF-8"); //to encode
URLDecoder.decode(myEncodedstring, "UTF-8"); //to decode

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




जैसा कि अन्य ने कहा है, आपको उद्धरणों को शामिल करने वाले मूल्यों से बचने की आवश्यकता है। यहां सीए में एक छोटा सीएसवी रीडर है जो एम्बेडेड कोट्स और कैरिज रिटर्न समेत उद्धृत मानों का समर्थन करता है।

वैसे, यह यूनिट-परीक्षण कोड है। मैं इसे अभी पोस्ट कर रहा हूं क्योंकि यह सवाल बहुत कुछ प्रतीत होता है और अन्य सरल सीएसवी समर्थन करते समय अन्य लाइब्रेरी नहीं चाहते हैं।

आप इसे निम्नानुसार उपयोग कर सकते हैं:

using System;
public class test
{
    public static void Main()
    {
        using ( CsvReader reader = new CsvReader( "data.csv" ) )
        {
            foreach( string[] values in reader.RowEnumerator )
            {
                Console.WriteLine( "Row {0} has {1} values.", reader.RowIndex, values.Length );
            }
        }
        Console.ReadLine();
    }
}

यहां कक्षाएं हैं। ध्यान दें कि आप वैध सीएसवी लिखने के लिए Csv.Escape फ़ंक्शन का भी उपयोग कर सकते हैं।

using System.IO;
using System.Text.RegularExpressions;

public sealed class CsvReader : System.IDisposable
{
    public CsvReader( string fileName ) : this( new FileStream( fileName, FileMode.Open, FileAccess.Read ) )
    {
    }

    public CsvReader( Stream stream )
    {
        __reader = new StreamReader( stream );
    }

    public System.Collections.IEnumerable RowEnumerator
    {
        get {
            if ( null == __reader )
                throw new System.ApplicationException( "I can't start reading without CSV input." );

            __rowno = 0;
            string sLine;
            string sNextLine;

            while ( null != ( sLine = __reader.ReadLine() ) )
            {
                while ( rexRunOnLine.IsMatch( sLine ) && null != ( sNextLine = __reader.ReadLine() ) )
                    sLine += "\n" + sNextLine;

                __rowno++;
                string[] values = rexCsvSplitter.Split( sLine );

                for ( int i = 0; i < values.Length; i++ )
                    values[i] = Csv.Unescape( values[i] );

                yield return values;
            }

            __reader.Close();
        }
    }

    public long RowIndex { get { return __rowno; } }

    public void Dispose()
    {
        if ( null != __reader ) __reader.Dispose();
    }

    //============================================


    private long __rowno = 0;
    private TextReader __reader;
    private static Regex rexCsvSplitter = new Regex( @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))" );
    private static Regex rexRunOnLine = new Regex( @"^[^""]*(?:""[^""]*""[^""]*)*""[^""]*$" );
}

public static class Csv
{
    public static string Escape( string s )
    {
        if ( s.Contains( QUOTE ) )
            s = s.Replace( QUOTE, ESCAPED_QUOTE );

        if ( s.IndexOfAny( CHARACTERS_THAT_MUST_BE_QUOTED ) > -1 )
            s = QUOTE + s + QUOTE;

        return s;
    }

    public static string Unescape( string s )
    {
        if ( s.StartsWith( QUOTE ) && s.EndsWith( QUOTE ) )
        {
            s = s.Substring( 1, s.Length - 2 );

            if ( s.Contains( ESCAPED_QUOTE ) )
                s = s.Replace( ESCAPED_QUOTE, QUOTE );
        }

        return s;
    }


    private const string QUOTE = "\"";
    private const string ESCAPED_QUOTE = "\"\"";
    private static char[] CHARACTERS_THAT_MUST_BE_QUOTED = { ',', '"', '\n' };
}



आप इस तरह सीएसवी फ़ाइल पढ़ सकते हैं।

यह विभाजन का उपयोग करता है और रिक्त स्थान का ख्याल रखता है।

ArrayList List = new ArrayList();
static ServerSocket Server;
static Socket socket;
static ArrayList<Object> list = new ArrayList<Object>();


public static void ReadFromXcel() throws FileNotFoundException
{   
    File f = new File("Book.csv");
    Scanner in = new Scanner(f);
    int count  =0;
    String[] date;
    String[] name;
    String[] Temp = new String[10];
    String[] Temp2 = new String[10];
    String[] numbers;
    ArrayList<String[]> List = new ArrayList<String[]>();
    HashMap m = new HashMap();

         in.nextLine();
         date = in.nextLine().split(",");
         name = in.nextLine().split(",");
         numbers = in.nextLine().split(",");
         while(in.hasNext())
         {
             String[] one = in.nextLine().split(",");
             List.add(one);
         }
         int xount = 0;
         //Making sure the lines don't start with a blank
         for(int y = 0; y<= date.length-1; y++)
         {
             if(!date[y].equals(""))
             {   
                 Temp[xount] = date[y];
                 Temp2[xount] = name[y];
                 xount++;
             }
         }

         date = Temp;
         name =Temp2;
         int counter = 0;
         while(counter < List.size())
         {
             String[] list = List.get(counter);
             String sNo = list[0];
             String Surname = list[1];
             String Name = list[2];
             for(int x = 3; x < list.length; x++)
             {           
                 m.put(numbers[x], list[x]);
             }
            Object newOne = new newOne(sNo, Name, Surname, m, false);
             StudentList.add(s);
             System.out.println(s.sNo);
             counter++;
         }



आपकी भाषा के आधार पर, एक to_json विधि उपलब्ध हो सकती है। यह सीएसवी को तोड़ने वाली कई चीजों से बच जाएगा।







csv