Penolakan
Pembaruan 2014-12-01: Jawaban di bawah ini hanya berfungsi untuk satu format CSV yang sangat spesifik. Seperti yang ditunjukkan dengan benar oleh DG di komentar , solusi ini tidak sesuai dengan definisi CSV RFC 4180 dan juga tidak sesuai dengan format Microsoft Excel. Solusi ini hanya mendemonstrasikan bagaimana seseorang dapat mengurai satu baris input CSV (non-standar) yang berisi campuran jenis string, di mana string mungkin berisi tanda kutip dan koma yang lolos.
Solusi CSV non-standar
Seperti yang ditunjukkan austincheney dengan benar , Anda benar-benar perlu mengurai string dari awal hingga akhir jika Anda ingin menangani string yang dikutip dengan benar yang mungkin berisi karakter yang lolos. Selain itu, OP tidak secara jelas mendefinisikan apa itu "string CSV" sebenarnya. Pertama kita harus menentukan apa yang merupakan string CSV yang valid dan nilai individualnya.
Diberikan: Definisi "CSV String"
Untuk tujuan diskusi ini, "string CSV" terdiri dari nol atau lebih nilai, di mana beberapa nilai dipisahkan oleh koma. Setiap nilai dapat terdiri dari:
- String kutip ganda (mungkin berisi tanda kutip tunggal yang tidak di-escape).
- String kutipan tunggal (mungkin berisi tanda kutip ganda yang tidak di-escape).
- String yang tidak dikutip ( tidak boleh berisi tanda kutip, koma, atau garis miring terbalik).
- Nilai kosong. (Nilai semua spasi kosong dianggap kosong.)
Aturan / Catatan:
- Nilai yang dikutip mungkin berisi koma.
- Nilai yang dikutip dapat berisi apa pun yang lolos, mis
'that\'s cool'
.
- Nilai yang mengandung kutipan, koma, atau garis miring terbalik harus dikutip.
- Nilai yang mengandung spasi kosong di depan atau di belakang harus dikutip.
- Garis miring terbalik dihapus dari semua:
\'
dalam nilai kutip tunggal.
- Garis miring terbalik dihapus dari semua:
\"
dalam nilai kutip ganda.
- String yang tidak dikutip akan dipangkas dari spasi di depan dan di belakangnya.
- Pemisah koma mungkin memiliki spasi yang berdekatan (yang diabaikan).
Temukan:
Fungsi JavaScript yang mengubah string CSV yang valid (seperti yang didefinisikan di atas) menjadi larik nilai string.
Larutan:
Ekspresi reguler yang digunakan oleh solusi ini kompleks. Dan (IMHO) semua ekspresi reguler non-sepele harus disajikan dalam mode spasi bebas dengan banyak komentar dan lekukan. Sayangnya, JavaScript tidak mengizinkan mode spasi bebas. Dengan demikian, ekspresi reguler yang diterapkan oleh solusi ini pertama kali disajikan dalam sintaks ekspresi reguler asli (diekspresikan menggunakan handy Pythonr'''...'''
sintaks string mentah-multi-baris ).
Pertama di sini adalah ekspresi reguler yang memvalidasi bahwa string CVS memenuhi persyaratan di atas:
Ekspresi reguler untuk memvalidasi "string 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.
"""
Jika sebuah string cocok dengan ekspresi reguler di atas, string tersebut adalah string CSV yang valid (sesuai dengan aturan yang dinyatakan sebelumnya) dan dapat diurai menggunakan ekspresi reguler berikut. Ekspresi reguler berikut kemudian digunakan untuk mencocokkan satu nilai dari string CSV. Ini diterapkan berulang kali hingga tidak ada lagi kecocokan yang ditemukan (dan semua nilai telah diuraikan).
Ekspresi reguler untuk mengurai satu nilai dari string CSV yang valid:
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.
"""
Perhatikan bahwa ada satu nilai kasus khusus yang tidak cocok dengan ekspresi reguler ini - nilai terakhir bila nilai itu kosong. Kasus khusus "nilai terakhir kosong" ini diuji dan ditangani oleh fungsi JavaScript yang mengikuti.
Fungsi JavaScript untuk mengurai string 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;
};
Contoh masukan dan keluaran:
Dalam contoh berikut, kurung kurawal digunakan untuk membatasi {result strings}
. (Ini untuk membantu memvisualisasikan spasi depan / belakang dan string panjang-nol.)
// 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] = {} */
Catatan tambahan:
Solusi ini mengharuskan string CSV menjadi "valid". Misalnya, nilai tanpa tanda kutip tidak boleh berisi garis miring terbalik atau tanda kutip, misalnya string CSV berikut tidak valid:
var invalid1 = "one, that's me!, escaped \, comma"
Ini sebenarnya bukan batasan karena setiap sub-string dapat direpresentasikan sebagai nilai kutip tunggal atau ganda. Perhatikan juga bahwa solusi ini hanya mewakili satu kemungkinan definisi untuk "nilai yang dipisahkan koma".
Edit riwayat
- 2014-05-19: Penafian tambahan.
- 2014-12-01: Penafian dipindahkan ke atas.