मैं जावास्क्रिप्ट के साथ CSV स्ट्रिंग को पार्स कैसे कर सकता हूं, जिसमें डेटा में कॉमा है?


93

मेरे पास निम्नलिखित प्रकार के स्ट्रिंग हैं

var string = "'string, duppi, du', 23, lala"

मैं प्रत्येक कॉमा पर एक सरणी में स्ट्रिंग को विभाजित करना चाहता हूं, लेकिन एकल उद्धरण चिह्नों के बाहर केवल कॉमा।

मैं विभाजन के लिए सही नियमित अभिव्यक्ति का पता नहीं लगा सकता ...

string.split(/,/)

मुझे दे देंगे

["'string", " duppi", " du'", " 23", " lala"]

लेकिन परिणाम यह होना चाहिए:

["string, duppi, du", "23", "lala"]

क्या कोई क्रॉस-ब्राउज़र समाधान है?


क्या यह हमेशा एकल-उद्धरण है? क्या कभी किसी उद्धृत स्ट्रिंग के अंदर एक एकल-उद्धरण है? यदि हां, तो यह कैसे बच गया है (बैकस्लैश, दोगुना-अप)?
फ़िरोज़

यदि जावास्क्रिप्ट और HTML / XML कोड में दोहरे और एकल उद्धरण वर्णों के बीच बोली वर्ण पूरी तरह से विनिमेय हैं, तो क्या होगा? यदि ऐसा है तो इसके लिए एक अधिक व्यापक पार्सिंग ऑपरेशन की आवश्यकता है जो सी.एस.वी.
austincheney

वास्तव में हाँ, वहाँ एक भी उद्धरण हो सकता है, बैकस्लैश के साथ भागना ठीक होगा।
हंस

क्या एक मूल्य एक दोहरे उद्धृत स्ट्रिंग हो सकता है?
१०

1
पापा पारसे अच्छा काम करते हैं। जावास्क्रिप्ट और पापा पार्स के साथ एक स्थानीय CSV फ़ाइल पार्स करना: joyofdata.de/blog/…
Raffael

जवाबों:


214

अस्वीकरण

2014-12-01 अपडेट: नीचे दिया गया उत्तर केवल CSV के एक बहुत विशिष्ट प्रारूप के लिए काम करता है। के रूप में सही ढंग से बताया टिप्पणी में महानिदेशक द्वारा , यह समाधान है नहीं सीएसवी के आरएफसी 4180 परिभाषा फिट और यह भी करता है नहीं माइक्रोसॉफ्ट एक्सेल प्रारूप फिट। यह समाधान केवल यह दर्शाता है कि इनपुट के एक (गैर-मानक) सीएसवी लाइन को कैसे पार्स किया जा सकता है जिसमें स्ट्रिंग प्रकारों का मिश्रण होता है, जहां तार में बच गए उद्धरण और अल्पविराम शामिल हो सकते हैं।

एक गैर-मानक सीएसवी समाधान

के रूप में austincheney सही ढंग से बताते हैं , आप वास्तव में शुरू से अंत तक स्ट्रिंग को पार्स करने की आवश्यकता है यदि आप उद्धृत किए गए वर्णों को ठीक से संभालना चाहते हैं जो बच गए अक्षर हो सकते हैं। इसके अलावा, ओपी स्पष्ट रूप से परिभाषित नहीं करता है कि वास्तव में "सीएसवी स्ट्रिंग" क्या है। पहले हमें यह निर्धारित करना चाहिए कि एक वैध सीएसवी स्ट्रिंग और उसके व्यक्तिगत मूल्य क्या हैं।

दिया गया: "सीएसवी स्ट्रिंग" परिभाषा

इस चर्चा के उद्देश्य के लिए, एक "सीएसवी स्ट्रिंग" में शून्य या अधिक मूल्य होते हैं, जहां कई मानों को अल्पविराम द्वारा अलग किया जाता है। प्रत्येक मूल्य में निम्न शामिल हो सकते हैं:

  1. एक डबल उद्धृत स्ट्रिंग (इसमें बिना उद्धरण के एकल उद्धरण हो सकते हैं)।
  2. एक सिंगल कोटेड स्ट्रिंग (इसमें अनसैप्ड डबल कोट्स हो सकते हैं)।
  3. एक गैर-उद्धृत स्ट्रिंग ( इसमें उद्धरण, अल्पविराम या बैकस्लैश शामिल नहीं हो सकते हैं)।
  4. एक खाली मान। (सभी व्हाट्सएप मूल्य को खाली माना जाता है।)

नियमों / नोट्स:

  • कोट किए गए मानों में अल्पविराम हो सकते हैं।
  • कोट किए गए मानों में कुछ भी हो सकता है, उदाहरण के लिए 'that\'s cool'
  • उद्धरण, अल्पविराम या बैकस्लैश वाले मान उद्धृत किए जाने चाहिए।
  • व्हाट्सएप के प्रमुख या अनुगामी वाले मानों को उद्धृत किया जाना चाहिए।
  • बैकस्लैश को सभी से हटा दिया जाता है: \'एकल उद्धृत मूल्यों में।
  • बैकलैश को सभी से हटा दिया जाता है: \"दोहरे उद्धृत मूल्यों में।
  • गैर-उद्धृत स्ट्रिंग्स को किसी भी अग्रणी और अनुगामी रिक्त स्थान की छंटनी की जाती है।
  • अल्पविराम विभाजक में आसन्न व्हाट्सएप हो सकता है (जिसे अनदेखा किया गया है)।

खोजें:

एक जावास्क्रिप्ट फ़ंक्शन जो स्ट्रिंग मानों की एक सरणी में एक मान्य CSV स्ट्रिंग (जैसा कि ऊपर परिभाषित किया गया है) को परिवर्तित करता है।

उपाय:

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

पहले यहां एक नियमित अभिव्यक्ति है जो पुष्टि करती है कि सीवीएस स्ट्रिंग उपरोक्त आवश्यकताओं को पूरा करती है:

"CSV स्ट्रिंग" को मान्य करने के लिए नियमित अभिव्यक्ति:

re_valid = r"""
# Validate a CSV string having single, double or un-quoted values.
^                                   # Anchor to start of string.
\s*                                 # Allow whitespace before value.
(?:                                 # Group for value alternatives.
  '[^'\\]*(?:\\[\S\s][^'\\]*)*'     # Either Single quoted string,
| "[^"\\]*(?:\\[\S\s][^"\\]*)*"     # or Double quoted string,
| [^,'"\s\\]*(?:\s+[^,'"\s\\]+)*    # or Non-comma, non-quote stuff.
)                                   # End group of value alternatives.
\s*                                 # Allow whitespace after value.
(?:                                 # Zero or more additional values
  ,                                 # Values separated by a comma.
  \s*                               # Allow whitespace before value.
  (?:                               # Group for value alternatives.
    '[^'\\]*(?:\\[\S\s][^'\\]*)*'   # Either Single quoted string,
  | "[^"\\]*(?:\\[\S\s][^"\\]*)*"   # or Double quoted string,
  | [^,'"\s\\]*(?:\s+[^,'"\s\\]+)*  # or Non-comma, non-quote stuff.
  )                                 # End group of value alternatives.
  \s*                               # Allow whitespace after value.
)*                                  # Zero or more additional values
$                                   # Anchor to end of string.
"""

यदि एक स्ट्रिंग उपरोक्त नियमित अभिव्यक्ति से मेल खाती है, तो वह स्ट्रिंग एक मान्य CSV स्ट्रिंग है (पहले बताए गए नियमों के अनुसार) और निम्नलिखित नियमित अभिव्यक्ति का उपयोग करके पार्स किया जा सकता है। फिर निम्न नियमित अभिव्यक्ति का उपयोग CSV स्ट्रिंग से एक मान से मेल खाने के लिए किया जाता है। यह तब तक बार-बार लागू किया जाता है जब तक कि कोई अधिक मिलान नहीं मिलता है (और सभी मानों को पार्स किया गया है)।

एक मान्य CSV स्ट्रिंग से एक मान पार्स करने के लिए नियमित अभिव्यक्ति:

re_value = r"""
# Match one value in valid CSV string.
(?!\s*$)                            # Don't match empty last value.
\s*                                 # Strip whitespace before value.
(?:                                 # Group for value alternatives.
  '([^'\\]*(?:\\[\S\s][^'\\]*)*)'   # Either $1: Single quoted string,
| "([^"\\]*(?:\\[\S\s][^"\\]*)*)"   # or $2: Double quoted string,
| ([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)  # or $3: Non-comma, non-quote stuff.
)                                   # End group of value alternatives.
\s*                                 # Strip whitespace after value.
(?:,|$)                             # Field ends on comma or EOS.
"""

ध्यान दें कि एक विशेष मामला मूल्य है जो इस नियमित अभिव्यक्ति से मेल नहीं खाता है - उस मूल्य के खाली होने पर बहुत अंतिम मूल्य। इस विशेष "रिक्त अंतिम मान" मामले का परीक्षण और जावास्क्रिप्ट फ़ंक्शन द्वारा नियंत्रित किया जाता है जो निम्नानुसार है।

CSV स्ट्रिंग को पार्स करने के लिए जावास्क्रिप्ट फ़ंक्शन:

// Return array of string values, or NULL if CSV string not well formed.
function CSVtoArray(text) {
    var re_valid = /^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/;
    var re_value = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;

    // Return NULL if input string is not well formed CSV string.
    if (!re_valid.test(text)) return null;

    var a = []; // Initialize array to receive values.
    text.replace(re_value, // "Walk" the string using replace with callback.
        function(m0, m1, m2, m3) {

            // Remove backslash from \' in single quoted values.
            if (m1 !== undefined) a.push(m1.replace(/\\'/g, "'"));

            // Remove backslash from \" in double quoted values.
            else if (m2 !== undefined) a.push(m2.replace(/\\"/g, '"'));
            else if (m3 !== undefined) a.push(m3);
            return ''; // Return empty string.
        });

    // Handle special case of empty last value.
    if (/,\s*$/.test(text)) a.push('');
    return a;
};

उदाहरण इनपुट और आउटपुट:

निम्नलिखित उदाहरणों में, घुंघराले ब्रेसिज़ का परिसीमन करने के लिए उपयोग किया जाता है {result strings}। (यह अग्रणी / अनुगामी स्थानों और शून्य-लंबाई के तारों की कल्पना करने में मदद करने के लिए है।)

// Test 1: Test string from original question.
var test = "'string, duppi, du', 23, lala";
var a = CSVtoArray(test);
/* Array has three elements:
    a[0] = {string, duppi, du}
    a[1] = {23}
    a[2] = {lala} */
// Test 2: Empty CSV string.
var test = "";
var a = CSVtoArray(test);
/* Array has zero elements: */
// Test 3: CSV string with two empty values.
var test = ",";
var a = CSVtoArray(test);
/* Array has two elements:
    a[0] = {}
    a[1] = {} */
// Test 4: Double quoted CSV string having single quoted values.
var test = "'one','two with escaped \' single quote', 'three, with, commas'";
var a = CSVtoArray(test);
/* Array has three elements:
    a[0] = {one}
    a[1] = {two with escaped ' single quote}
    a[2] = {three, with, commas} */
// Test 5: Single quoted CSV string having double quoted values.
var test = '"one","two with escaped \" double quote", "three, with, commas"';
var a = CSVtoArray(test);
/* Array has three elements:
    a[0] = {one}
    a[1] = {two with escaped " double quote}
    a[2] = {three, with, commas} */
// Test 6: CSV string with whitespace in and around empty and non-empty values.
var test = "   one  ,  'two'  ,  , ' four' ,, 'six ', ' seven ' ,  ";
var a = CSVtoArray(test);
/* Array has eight elements:
    a[0] = {one}
    a[1] = {two}
    a[2] = {}
    a[3] = { four}
    a[4] = {}
    a[5] = {six }
    a[6] = { seven }
    a[7] = {} */

अतिरिक्त नोट्स:

इस समाधान के लिए आवश्यक है कि CSV स्ट्रिंग "मान्य" हो। उदाहरण के लिए, अछूता मान में बैकस्लैश या उद्धरण शामिल नहीं हो सकते हैं, उदाहरण के लिए निम्न CSV स्ट्रिंग मान्य नहीं है:

var invalid1 = "one, that's me!, escaped \, comma"

यह वास्तव में एक सीमा नहीं है क्योंकि किसी भी उप-स्ट्रिंग को एकल या दोहरे उद्धृत मूल्य के रूप में दर्शाया जा सकता है। ध्यान दें कि यह समाधान "अल्पविराम से अलग किए गए मान" के लिए केवल एक संभावित परिभाषा का प्रतिनिधित्व करता है।

इतिहास संपादित करें

  • 2014-05-19: जोड़ा गया अस्वीकरण।
  • 2014-12-01: शीर्ष पर अस्वीकरण स्थानांतरित कर दिया।

1
@ इवान प्लाइस - अच्छे शब्दों के लिए धन्यवाद। सुनिश्चित करें कि आप किसी भी विभाजक का उपयोग कर सकते हैं। बस चुनाव के विभाजक के साथ मेरे regex में हर अल्पविराम को बदलें (लेकिन विभाजक को व्हाट्सएप नहीं किया जा सकता है)। चीयर्स।
राइडरुननर

2
@ इवान प्लाइस - आप किसी भी उद्देश्य के लिए मेरी इच्छा के किसी भी उपयोग का स्वागत करते हैं। मान्यता का एक नोट अच्छा होगा लेकिन आवश्यक नहीं है। अपने प्लग-इन के साथ शुभकामनाएँ। चीयर्स!
सवार

1
कूल, यहां प्रोजेक्ट कोड है । Googlep/jquery-csv । आखिरकार, मैं SSV (स्ट्रक्चर्ड सेपरेटेड वैल्यूज़) नामक CSV में एक एक्सटेंशन फॉर्मेट जोड़ना चाहता हूं, जिसमें बस मेटाडाटा (यानी, सीमांकक, विभाजक, लाइन समाप्त होने, आदि) के साथ CSV शामिल है।
इवान प्लाइस

1
इस महान कार्यान्वयन के लिए बहुत बहुत धन्यवाद - मैंने इसे Node.js मॉड्यूल ( csv-iterator ) के लिए आधार के रूप में उपयोग किया ।
mirkokiefer

3
मैं विस्तार से सराहना करता हूं और आपके उत्तर को स्पष्ट करता हूं, लेकिन यह कहीं न कहीं ध्यान दिया जाना चाहिए कि सीएसवी की आपकी परिभाषा आरएफसी 4180 फिट नहीं होती है जो कि सीएसवी के लिए एक मानक चीज है, और जो मैं कह सकता हूं कि इसका आमतौर पर उपयोग किया जाता है। विशेष रूप से यह एक स्ट्रिंग क्षेत्र के भीतर एक दोहरे उद्धरण चरित्र को "बचने" का सामान्य तरीका होगा: "field one", "field two", "a ""final"" field containing two double quote marks"मैंने इस पृष्ठ पर ट्रेवर डिक्सन के उत्तर का परीक्षण नहीं किया है, लेकिन यह एक उत्तर है जो सीएसवी की आरएफसी 4180 परिभाषा को संबोधित करता है।
डीजी।

53

आरएफसी 4180 समाधान

यह प्रश्न में स्ट्रिंग को हल नहीं करता है क्योंकि इसका प्रारूप RFC 4180 के अनुरूप नहीं है; स्वीकार्य एन्कोडिंग दोहरे उद्धरण के साथ दोहरे उद्धरण से बच रहा है। नीचे दिया गया समाधान Google स्प्रेडशीट से CSV फ़ाइलों d / l के साथ सही ढंग से काम करता है।

अद्यतन (3/2017)

सिंगल लाइन को पार्स करना गलत होगा। RFC के अनुसार 4180 फ़ील्ड में CRLF हो सकता है जो CSV फ़ाइल को तोड़ने के लिए किसी भी लाइन रीडर का कारण होगा। यहाँ एक अद्यतन संस्करण है जो CSV स्ट्रिंग को पार्स करता है:

'use strict';

function csvToArray(text) {
    let p = '', row = [''], ret = [row], i = 0, r = 0, s = !0, l;
    for (l of text) {
        if ('"' === l) {
            if (s && l === p) row[i] += l;
            s = !s;
        } else if (',' === l && s) l = row[++i] = '';
        else if ('\n' === l && s) {
            if ('\r' === p) row[i] = row[i].slice(0, -1);
            row = ret[++r] = [l = '']; i = 0;
        } else row[i] += l;
        p = l;
    }
    return ret;
};

let test = '"one","two with escaped """" double quotes""","three, with, commas",four with no quotes,"five with CRLF\r\n"\r\n"2nd line one","two with escaped """" double quotes""","three, with, commas",four with no quotes,"five with CRLF\r\n"';
console.log(csvToArray(test));

पुराने ANSWER

(सिंगल लाइन समाधान)

function CSVtoArray(text) {
    let ret = [''], i = 0, p = '', s = true;
    for (let l in text) {
        l = text[l];
        if ('"' === l) {
            s = !s;
            if ('"' === p) {
                ret[i] += '"';
                l = '-';
            } else if ('' === p)
                l = '-';
        } else if (s && ',' === l)
            l = ret[++i] = '';
        else
            ret[i] += l;
        p = l;
    }
    return ret;
}
let test = '"one","two with escaped """" double quotes""","three, with, commas",four with no quotes,five for fun';
console.log(CSVtoArray(test));

और मज़े के लिए, यहाँ आप सरणी से CSV कैसे बना सकते हैं:

function arrayToCSV(row) {
    for (let i in row) {
        row[i] = row[i].replace(/"/g, '""');
    }
    return '"' + row.join('","') + '"';
}

let row = [
  "one",
  "two with escaped \" double quote",
  "three, with, commas",
  "four with no quotes (now has)",
  "five for fun"
];
let text = arrayToCSV(row);
console.log(text);


1
इसने मेरे लिए काम किया, अन्य एक नहीं
WtFudgE

7

PEG (.js) व्याकरण जो RFC 4180 उदाहरणों को http://en.wikipedia.org/wiki/Comma-separated_values पर हैंडल करता है :

start
  = [\n\r]* first:line rest:([\n\r]+ data:line { return data; })* [\n\r]* { rest.unshift(first); return rest; }

line
  = first:field rest:("," text:field { return text; })*
    & { return !!first || rest.length; } // ignore blank lines
    { rest.unshift(first); return rest; }

field
  = '"' text:char* '"' { return text.join(''); }
  / text:[^\n\r,]* { return text.join(''); }

char
  = '"' '"' { return '"'; }
  / [^"]

Http://jsfiddle.net/knvzk/10 या https://pegjs.org/online पर परीक्षण करें

उत्पन्न पार्सर को https://gist.github.com/3362830 पर डाउनलोड करें


6

मेरे पास एक बहुत विशिष्ट उपयोग का मामला था जहां मैं Google शीट से कोशिकाओं को अपने वेब ऐप में कॉपी करना चाहता था। सेल में दोहरे-उद्धरण और नए-पंक्ति वर्ण शामिल हो सकते हैं। कॉपी और पेस्ट का उपयोग करके, कोशिकाओं को टैब वर्णों द्वारा सीमांकित किया जाता है, और विषम डेटा वाले सेल डबल उद्धृत होते हैं। मैंने इस मुख्य समाधान की कोशिश की, रीग्रैक्सपी और जेक्वेरी-सीएसवी, और सीएसवीटॉअर्रे का उपयोग करके जुड़ा हुआ लेख। http://papaparse.com/ केवल वही है जिसने बॉक्स से बाहर काम किया है। Google ऑटो के साथ डिफ़ॉल्ट ऑटो-डिटेक्ट विकल्पों के साथ कॉपी और पेस्ट करना सहज है।


1
इसे बहुत अधिक रैंक किया जाना चाहिए, कभी भी अपने स्वयं के सीएसवी पार्सर को रोल करने की कोशिश न करें, यह सही ढंग से काम नहीं करेगा - विशेष रूप से रेग्जेस का उपयोग करते समय। Papaparse कमाल है - इसका उपयोग करें!
cbley

6

मुझे FakeRainBrigand का जवाब पसंद आया, हालांकि इसमें कुछ समस्याएं हैं: यह एक उद्धरण और अल्पविराम के बीच व्हाट्सएप को नहीं संभाल सकता है, और लगातार 2 कॉमा का समर्थन नहीं करता है। मैंने उनके उत्तर को संपादित करने की कोशिश की, लेकिन समीक्षकों द्वारा मेरे संपादन को अस्वीकार कर दिया गया, जो कि स्पष्ट रूप से मेरे कोड को नहीं समझते थे। यहाँ FakeRainBrigand के कोड का मेरा संस्करण है। एक बेला भी है: http://jsfiddle.net/xTezm/46/

String.prototype.splitCSV = function() {
        var matches = this.match(/(\s*"[^"]+"\s*|\s*[^,]+|,)(?=,|$)/g);
        for (var n = 0; n < matches.length; ++n) {
            matches[n] = matches[n].trim();
            if (matches[n] == ',') matches[n] = '';
        }
        if (this[0] == ',') matches.unshift("");
        return matches;
}

var string = ',"string, duppi, du" , 23 ,,, "string, duppi, du",dup,"", , lala';
var parsed = string.splitCSV();
alert(parsed.join('|'));

4

लोग इसके लिए RegEx के खिलाफ लग रहे थे। क्यों?

(\s*'[^']+'|\s*[^,]+)(?=,|$)

यहाँ कोड है। मैंने एक फील भी किया ।

String.prototype.splitCSV = function(sep) {
  var regex = /(\s*'[^']+'|\s*[^,]+)(?=,|$)/g;
  return matches = this.match(regex);    
}

var string = "'string, duppi, du', 23, 'string, duppi, du', lala";
var parsed = string.splitCSV();
alert(parsed.join('|'));

3
हम्म, आपके regexp में कुछ मुद्दे हैं: यह एक उद्धरण और अल्पविराम के बीच व्हाट्सएप को संभाल नहीं सकता है, और लगातार 2 अल्पविराम का समर्थन नहीं करता है। मैंने आपके उत्तर को कोड के साथ अपडेट किया है जो दोनों मुद्दों को ठीक करता है और एक नया
फील किया है

किसी कारण से आपके कोड के लिए मेरा संपादन अस्वीकार कर दिया गया था क्योंकि यह "पोस्ट के मूल इरादे से विचलित" होगा। बहुत अजीब!? मैंने सिर्फ आपका कोड लिया और इसके साथ दो समस्याएं तय कीं। यह पोस्ट के इरादे को कैसे बदलता है !? वैसे भी ... मैं बस इस सवाल का एक नया जवाब जोड़ रहा हूँ।
HammerNL

आपके उत्तर में अच्छा प्रश्न, @FakeRainBrigand। मैं रेगेक्स के लिए एक सब के लिए, और उसके कारण, मैं स्वीकार करता हूं कि यह नौकरी के लिए गलत उपकरण है।
niry

2
@niry यहाँ मेरा कोड भयानक है। मैं वादा करता हूँ कि मैं पिछले 6 वर्षों में बेहतर हो गया हूँ:
ब्रिगैंड

4

इस सूची में और एक जोड़ा जा रहा है, क्योंकि मैं ऊपर काफी नहीं "किस" पर्याप्त के सभी पाते हैं।

उद्धृत वस्तुओं पर लंघन करते समय यह या तो कॉमा या न्यूलाइन्स खोजने के लिए रेगेक्स का उपयोग करता है। उम्मीद है कि यह कुछ है noobies के माध्यम से अपने दम पर पढ़ सकते हैं। splitFinderRegexp तीन बातें यह (एक से विभाजित करता है |):

  1. , - अल्पविराम पाता है
  2. \r?\n - नई लाइनें पाता है, (संभावित रूप से गाड़ी वापसी के साथ अगर निर्यातक अच्छा था)
  3. "(\\"|[^"])*?"- उद्धरणों में घिरी किसी भी चीज़ को छोड़ दें, क्योंकि कॉमा और न्यूलाइन्स वहाँ मायने नहीं रखते। यदि \\"उद्धृत आइटम में कोई बची हुई बोली है, तो अंतिम उद्धरण मिलने से पहले उसे पकड़ लिया जाएगा।

const splitFinder = /,|\r?\n|"(\\"|[^"])*?"/g;

function csvTo2dArray(parseMe) {
  let currentRow = [];
  const rowsOut = [currentRow];
  let lastIndex = splitFinder.lastIndex = 0;
  
  // add text from lastIndex to before a found newline or comma
  const pushCell = (endIndex) => {
    endIndex = endIndex || parseMe.length;
    const addMe = parseMe.substring(lastIndex, endIndex);
    // remove quotes around the item
    currentRow.push(addMe.replace(/^"|"$/g, ""));
    lastIndex = splitFinder.lastIndex;
  }


  let regexResp;
  // for each regexp match (either comma, newline, or quoted item)
  while (regexResp = splitFinder.exec(parseMe)) {
    const split = regexResp[0];

    // if it's not a quote capture, add an item to the current row
    // (quote captures will be pushed by the newline or comma following)
    if (split.startsWith(`"`) === false) {
      const splitStartIndex = splitFinder.lastIndex - split.length;
      pushCell(splitStartIndex);

      // then start a new row if newline
      const isNewLine = /^\r?\n$/.test(split);
      if (isNewLine) { rowsOut.push(currentRow = []); }
    }
  }
  // make sure to add the trailing text (no commas or newlines after)
  pushCell();
  return rowsOut;
}

const rawCsv = `a,b,c\n"test\r\n","comma, test","\r\n",",",\nsecond,row,ends,with,empty\n"quote\"test"`
const rows = csvTo2dArray(rawCsv);
console.log(rows);


अगर मैं अपनी फाइल को fileReader और मेरे परिणाम के माध्यम से पढ़ता हूं: Id, Name, Age 1, John Smith, 65 2, Jane Doe, 30 मैं अपने द्वारा निर्दिष्ट कॉलम के आधार पर पार्स कैसे कर सकता हूं?
ब्लूपार्क

आपके द्वारा 2d सरणी प्राप्त करने के बाद, पहले अनुक्रमणिका को हटा दें (यह जो आपके प्रोप नाम हैं), फिर बाकी सरणी पर पुनरावृति करें, प्रत्येक गुण के साथ ऑब्जेक्ट को एक संपत्ति के रूप में बनाएं। यह इस तरह दिखेगा:[{Id: 1, Name: "John Smith", Age: 65}, {Id: 2, Name: "Jane Doe", Age: 30}]
सिपाही रीड

3

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

आप या तो पहले सिंगल-कोट्स को डबल-कोट्स में ट्रांसलेट कर सकते हैं:

string = string.replace( /'/g, '"' );

... या आप उस प्रश्न में रेगेक्स को डबल-कोट्स के बजाय सिंगल-कोट्स को पहचान सकते हैं:

// Quoted fields.
"(?:'([^']*(?:''[^']*)*)'|" +

हालाँकि, यह कुछ मार्कअप मानता है जो आपके प्रश्न से स्पष्ट नहीं है। कृपया स्पष्ट करें कि मार्कअप की सभी विभिन्न संभावनाएँ आपके प्रश्न पर मेरी टिप्पणी के अनुसार हो सकती हैं।


2

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

आप इसके लिए regex का उपयोग नहीं कर सकते। वास्तव में आपको उस विभाजन का विश्लेषण करने के लिए एक माइक्रो पार्सर लिखना होगा जिसे आप विभाजित करना चाहते हैं। मैं इस उत्तर के लिए, आपके तारों के उद्धृत भागों को उप-स्ट्रिंग के रूप में कॉल करूंगा। आपको विशेष रूप से स्ट्रिंग में चलने की आवश्यकता है। निम्नलिखित मामले पर विचार करें:

var a = "some sample string with \"double quotes\" and 'single quotes' and some craziness like this: \\\" or \\'",
    b = "sample of code from JavaScript with a regex containing a comma /\,/ that should probably be ignored.";

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

मैं आपके लिए कोड की जटिलता के उस स्तर को लिखने नहीं जा रहा हूं, लेकिन आप हाल ही में लिखी गई कुछ चीजों को देख सकते हैं, जिसकी आपको जरूरत है। इस कोड का अल्पविराम से कोई लेना-देना नहीं है, लेकिन अन्यथा आपके पास अपने कोड लिखने में अनुसरण करने के लिए एक वैध पर्याप्त माइक्रो-पार्सर है। निम्नलिखित आवेदन के asifix समारोह में देखो:

https://github.com/austincheney/Pretty-Diff/blob/master/fulljsmin.js


2

इस उत्तर के पूरक के लिए

यदि आपको उद्धरण देने की आवश्यकता है, तो दूसरे उद्धरण के साथ भाग गए, उदाहरण:

"some ""value"" that is on xlsx file",123

आप उपयोग कर सकते हैं

function parse(text) {
  const csvExp = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|"([^""]*(?:"[\S\s][^""]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;

  const values = [];

  text.replace(csvExp, (m0, m1, m2, m3, m4) => {
    if (m1 !== undefined) {
      values.push(m1.replace(/\\'/g, "'"));
    }
    else if (m2 !== undefined) {
      values.push(m2.replace(/\\"/g, '"'));
    }
    else if (m3 !== undefined) {
      values.push(m3.replace(/""/g, '"'));
    }
    else if (m4 !== undefined) {
      values.push(m4);
    }
    return '';
  });

  if (/,\s*$/.test(text)) {
    values.push('');
  }

  return values;
}

मैंने पाया कि यह अभी भी पार्सिंग में विफल रहता है"jjj "" kkk""","123"
14

2

CSV फ़ाइल को स्ट्रिंग में पढ़ते समय, इसमें स्ट्रिंग के बीच में शून्य मान होते हैं, इसलिए इसे लाइन द्वारा \ 0 लाइन के साथ आज़माएं । इससे मेरा काम बनता है।

stringLine = stringLine.replace(/\0/g, "" );

2

मुझे उसी प्रकार की समस्या का सामना करना पड़ा है जब मुझे एक सीएसवी फ़ाइल को पार्स करना था।

फ़ाइल में एक स्तंभ पता होता है जिसमें ',' होता है।

उस CSV फ़ाइल को JSON में पार्स करने के बाद, मुझे इसे JSON फ़ाइल में परिवर्तित करने के दौरान कुंजियों की बेमेल मैपिंग मिलती है।

मैंने फाइल और पुस्तकालयों को बेबी पार्स और सीएसवेटजोन की तरह पार्स करने के लिए Node.js का उपयोग किया ।

फ़ाइल का उदाहरण -

address,pincode
foo,baar , 123456

जब मैं JSON में बेबी पार्स का उपयोग किए बिना सीधे पार्स कर रहा था, तो मुझे मिल रहा था:

[{
 address: 'foo',
 pincode: 'baar',
 'field3': '123456'
}]

इसलिए मैंने कोड लिखा जो हर क्षेत्र के साथ किसी अन्य परिसीमन के साथ अल्पविराम () हटाता है:

/*
 csvString(input) = "address, pincode\\nfoo, bar, 123456\\n"
 output = "address, pincode\\nfoo {YOUR DELIMITER} bar, 123455\\n"
*/
const removeComma = function(csvString){
    let delimiter = '|'
    let Baby = require('babyparse')
    let arrRow = Baby.parse(csvString).data;
    /*
      arrRow = [
      [ 'address', 'pincode' ],
      [ 'foo, bar', '123456']
      ]
    */
    return arrRow.map((singleRow, index) => {
        //the data will include
        /*
        singleRow = [ 'address', 'pincode' ]
        */
        return singleRow.map(singleField => {
            //for removing the comma in the feild
            return singleField.split(',').join(delimiter)
        })
    }).reduce((acc, value, key) => {
        acc = acc +(Array.isArray(value) ?
         value.reduce((acc1, val)=> {
            acc1 = acc1+ val + ','
            return acc1
        }, '') : '') + '\n';
        return acc;
    },'')
}

लौटाए गए फ़ंक्शन को csvtojson लाइब्रेरी में पास किया जा सकता है और इस प्रकार परिणाम का उपयोग किया जा सकता है।

const csv = require('csvtojson')

let csvString = "address, pincode\\nfoo, bar, 123456\\n"
let jsonArray = []
modifiedCsvString = removeComma(csvString)
csv()
  .fromString(modifiedCsvString)
  .on('json', json => jsonArray.push(json))
  .on('end', () => {
    /* do any thing with the json Array */
  })

अब आप आउटपुट प्राप्त कर सकते हैं जैसे:

[{
  address: 'foo, bar',
  pincode: 123456
}]

2

कोई regexp, पठनीय, और https://en.wikipedia.org/wiki/Comma-separated_values#Basic_rules के अनुसार :

function csv2arr(str: string) {
    let line = ["",];
    const ret = [line,];
    let quote = false;

    for (let i = 0; i < str.length; i++) {
        const cur = str[i];
        const next = str[i + 1];

        if (!quote) {
            const cellIsEmpty = line[line.length - 1].length === 0;
            if (cur === '"' && cellIsEmpty) quote = true;
            else if (cur === ",") line.push("");
            else if (cur === "\r" && next === "\n") { line = ["",]; ret.push(line); i++; }
            else if (cur === "\n" || cur === "\r") { line = ["",]; ret.push(line); }
            else line[line.length - 1] += cur;
        } else {
            if (cur === '"' && next === '"') { line[line.length - 1] += cur; i++; }
            else if (cur === '"') quote = false;
            else line[line.length - 1] += cur;
        }
    }
    return ret;
}

1

इस ब्लॉग पोस्ट के अनुसार , इस फ़ंक्शन को यह करना चाहिए:

String.prototype.splitCSV = function(sep) {
  for (var foo = this.split(sep = sep || ","), x = foo.length - 1, tl; x >= 0; x--) {
    if (foo[x].replace(/'\s+$/, "'").charAt(foo[x].length - 1) == "'") {
      if ((tl = foo[x].replace(/^\s+'/, "'")).length > 1 && tl.charAt(0) == "'") {
        foo[x] = foo[x].replace(/^\s*'|'\s*$/g, '').replace(/''/g, "'");
      } else if (x) {
        foo.splice(x - 1, 2, [foo[x - 1], foo[x]].join(sep));
      } else foo = foo.shift().split(sep).concat(foo);
    } else foo[x].replace(/''/g, "'");
  } return foo;
};

आप इसे इस तरह कहेंगे:

var string = "'string, duppi, du', 23, lala";
var parsed = string.splitCSV();
alert(parsed.join("|"));

यह jsfiddle तरह का काम करता है, लेकिन ऐसा लगता है कि कुछ तत्वों में उनके पहले स्थान हैं।


एक regex में वह सब करने की कल्पना करो। यही कारण है कि regexes कभी-कभी पार्स करने के लिए उपयुक्त नहीं होते हैं।
कैनस्पिस

यह समाधान बस काम नहीं करता है। मूल परीक्षण स्ट्रिंग को देखते हुए: "'string, duppi, du', 23, lala"यह फ़ंक्शन लौटाता है:["'string"," duppi"," du'"," 23"," lala"]
राइडरुनर

@ridgerunner: सही है आप। मैंने फ़ंक्शन को ठीक करने के लिए उत्तर और jsfiddle को संपादित किया है। असल में, मैं बंद "'"करने के लिए '"'और उपाध्यक्ष प्रतिकूल।
कैंसिसे

इसने मदद की, लेकिन अब फ़ंक्शन गलत रूप से दोहरे उद्धृत मूल्यों वाले एकल उद्धृत CSV स्ट्रिंग्स को संभालता है। जैसे मूल परीक्षण स्ट्रिंग के उद्धरण प्रकारों को '"string, duppi, du", 23, lala'['"string',' duppi'.' du"',' 23',' lala']
उल्टा करना

@CanSpice, आपकी टिप्पणी ने मुझे RegEx के साथ प्रयास करने के लिए प्रेरित किया। इसमें कई विशेषताएं नहीं हैं, लेकिन इन्हें आसानी से जोड़ा जा सकता है। (मेरा उत्तर इस पृष्ठ पर है, यदि आप रुचि रखते हैं।)
ब्रिगैंड

0

बचाव के लिए नियमित अभिव्यक्ति! कोड की ये कुछ पंक्तियाँ RFC 4180 मानक के आधार पर एम्बेडेड अल्पविराम, उद्धरण और नईलाइन्स के साथ ठीक से उद्धृत फ़ील्ड को हैंडल करती हैं।

function parseCsv(data, fieldSep, newLine) {
    fieldSep = fieldSep || ',';
    newLine = newLine || '\n';
    var nSep = '\x1D';
    var qSep = '\x1E';
    var cSep = '\x1F';
    var nSepRe = new RegExp(nSep, 'g');
    var qSepRe = new RegExp(qSep, 'g');
    var cSepRe = new RegExp(cSep, 'g');
    var fieldRe = new RegExp('(?<=(^|[' + fieldSep + '\\n]))"(|[\\s\\S]+?(?<![^"]"))"(?=($|[' + fieldSep + '\\n]))', 'g');
    var grid = [];
    data.replace(/\r/g, '').replace(/\n+$/, '').replace(fieldRe, function(match, p1, p2) {
        return p2.replace(/\n/g, nSep).replace(/""/g, qSep).replace(/,/g, cSep);
    }).split(/\n/).forEach(function(line) {
        var row = line.split(fieldSep).map(function(cell) {
            return cell.replace(nSepRe, newLine).replace(qSepRe, '"').replace(cSepRe, ',');
        });
        grid.push(row);
    });
    return grid;
}

const csv = 'A1,B1,C1\n"A ""2""","B, 2","C\n2"';
const separator = ',';      // field separator, default: ','
const newline = ' <br /> '; // newline representation in case a field contains newlines, default: '\n' 
var grid = parseCsv(csv, separator, newline);
// expected: [ [ 'A1', 'B1', 'C1' ], [ 'A "2"', 'B, 2', 'C <br /> 2' ] ]

जब तक कहीं और कहा गया है, आपको एक परिमित राज्य मशीन की आवश्यकता नहीं है। रेग्युलर एक्सप्रेशन RFC 4180 को पॉजिटिव लुकबाइंड, नेगेटिव लुकबाइंड और पॉजिटिव लुकहैड की बदौलत ठीक से हैंडल करता है।

Https://github.com/peterthoeny/parse-csv-js पर क्लोन / डाउनलोड कोड


0

राइडर से उत्कृष्ट और पूर्ण उत्तर के अलावा , जब आपका बैकएंड PHP चलाता है, तो मैंने बहुत ही सरल वर्कअराउंड के बारे में सोचा।

अपने डोमेन के बैकएंड को यह PHP फ़ाइल जोड़ें (कहते हैं: csv.php)

<?php
    session_start(); // Optional
    header("content-type: text/xml");
    header("charset=UTF-8");
    // Set the delimiter and the End of Line character of your CSV content:
    echo json_encode(array_map('str_getcsv', str_getcsv($_POST["csv"], "\n")));
?>

अब इस फ़ंक्शन को अपने जावास्क्रिप्ट टूलकिट में जोड़ें (मुझे विश्वास है कि क्रॉसब्रोसर बनाने के लिए थोड़ा संशोधित किया जाना चाहिए)।

function csvToArray(csv) {
    var oXhr = new XMLHttpRequest;
    oXhr.addEventListener("readystatechange",
        function () {
            if (this.readyState == 4 && this.status == 200) {
                console.log(this.responseText);
                console.log(JSON.parse(this.responseText));
            }
        }
    );
    oXhr.open("POST","path/to/csv.php",true);
    oXhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
    oXhr.send("csv=" + encodeURIComponent(csv));
}

यह आपको एक अजाक्स कॉल की कीमत देगा, लेकिन कम से कम आप कोड की नकल नहीं करेंगे और न ही किसी बाहरी पुस्तकालय को शामिल करेंगे।

Ref: http://php.net/manual/en/function.str-getcsv.php


0

आप नीचे दिए उदाहरण की तरह papaparse.js का उपयोग कर सकते हैं :

<!DOCTYPE html>
<html lang="en">

    <head>
        <title>CSV</title>
    </head>

    <body>
        <input type="file" id="files" multiple="">
        <button onclick="csvGetter()">CSV Getter</button>
        <h3>The Result will be in the Console.</h3>

        <script src="papaparse.min.js"></script>

        <script>
            function csvGetter() {

                var file = document.getElementById('files').files[0];
                Papa.parse(file, {
                    complete: function(results) {
                        console.log(results.data);
                    }
                });
            }
          </script>
    </body>

</html>

एक ही फ़ोल्डर में papaparse.js को शामिल करना न भूलें।

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