Khước từ
Cập nhật 2014-12-01: Câu trả lời bên dưới chỉ hoạt động cho một định dạng rất cụ thể của CSV. Như đã chỉ ra một cách chính xác bởi DG trong các nhận xét, giải pháp này KHÔNG phù hợp với định nghĩa RFC 4180 của CSV và nó cũng KHÔNG phù hợp với định dạng MS Excel. Giải pháp này chỉ đơn giản là minh họa cách người ta có thể phân tích cú pháp một dòng đầu vào CSV (không chuẩn) chứa hỗn hợp các loại chuỗi, trong đó các chuỗi có thể chứa dấu ngoặc kép và dấu phẩy.
Giải pháp CSV không chuẩn
Như austincheney đã chỉ ra một cách chính xác, bạn thực sự cần phải phân tích cú pháp chuỗi từ đầu đến cuối nếu bạn muốn xử lý đúng các chuỗi được trích dẫn có thể chứa các ký tự thoát. Ngoài ra, OP không xác định rõ ràng "chuỗi CSV" thực sự là gì. Trước tiên, chúng ta phải xác định những gì tạo thành một chuỗi CSV hợp lệ và các giá trị riêng lẻ của nó.
Đưa ra: Định nghĩa "Chuỗi CSV"
Đối với mục đích của cuộc thảo luận này, "chuỗi CSV" bao gồm 0 hoặc nhiều giá trị, trong đó nhiều giá trị được phân tách bằng dấu phẩy. Mỗi giá trị có thể bao gồm:
- Một chuỗi được trích dẫn kép. (có thể chứa các dấu nháy đơn không thoát.)
- Một chuỗi trích dẫn duy nhất. (có thể chứa dấu ngoặc kép không thoát.)
- Một chuỗi không được trích dẫn. (KHÔNG được chứa dấu ngoặc kép, dấu phẩy hoặc dấu gạch chéo ngược.)
- Một giá trị trống. (Một giá trị tất cả khoảng trắng được coi là trống.)
Quy tắc / Ghi chú:
- Giá trị được trích dẫn có thể chứa dấu phẩy.
- Giá trị niêm yết có thể chứa thoát-bất cứ điều gì, ví dụ
'that\'s cool'
.
- Các giá trị chứa dấu ngoặc kép, dấu phẩy hoặc dấu gạch chéo ngược phải được trích dẫn.
- Các giá trị chứa khoảng trắng đầu hoặc cuối phải được trích dẫn.
- Dấu gạch chéo ngược bị xóa khỏi tất cả:
\'
trong các giá trị được trích dẫn đơn lẻ.
- Dấu gạch chéo ngược bị xóa khỏi tất cả:
\"
trong các giá trị được trích dẫn kép.
- Các chuỗi không được trích dẫn được cắt bỏ mọi khoảng trống ở đầu và cuối.
- Dấu phân cách bằng dấu phẩy có thể có khoảng trắng liền kề (bị bỏ qua).
Tìm thấy:
Một hàm JavaScript chuyển đổi một chuỗi CSV hợp lệ (như được định nghĩa ở trên) thành một mảng các giá trị chuỗi.
Giải pháp:
Các biểu thức chính quy được sử dụng bởi giải pháp này rất phức tạp. Và (IMHO) tất cả các regex không tầm thường nên được trình bày ở chế độ khoảng cách tự do với nhiều chú thích và thụt lề. Thật không may, JavaScript không cho phép chế độ giãn cách tự do. Do đó, các biểu thức chính quy được triển khai bởi giải pháp này lần đầu tiên được trình bày trong cú pháp regex gốc (được thể hiện bằng cách sử dụng tiện dụng của Python:r'''...'''
cú pháp chuỗi thô-đa-dòng-chuỗi ).
Đầu tiên, đây là một biểu thức chính quy xác nhận rằng một chuỗi CVS đáp ứng các yêu cầu trên:
Regex để xác thực "chuỗi 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.
"""
Nếu một chuỗi khớp với regex ở trên, thì chuỗi đó là một chuỗi CSV hợp lệ (theo các quy tắc đã nêu trước đó) và có thể được phân tích cú pháp bằng cách sử dụng regex sau. Sau đó, regex sau được sử dụng để khớp với một giá trị từ chuỗi CSV. Nó được áp dụng lặp đi lặp lại cho đến khi không tìm thấy kết quả phù hợp nào nữa (và tất cả các giá trị đã được phân tích cú pháp).
Regex để phân tích cú pháp một giá trị từ chuỗi CSV hợp lệ:
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.
"""
Lưu ý rằng có một giá trị trường hợp đặc biệt mà regex này không khớp - giá trị cuối cùng khi giá trị đó trống. Trường hợp "giá trị cuối cùng trống" đặc biệt này được kiểm tra và xử lý bởi hàm js theo sau.
Hàm JavaScript để phân tích cú pháp chuỗi 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;
};
Ví dụ đầu vào và đầu ra:
Trong các ví dụ sau, dấu ngoặc nhọn được sử dụng để phân cách {result strings}
. (Điều này là để giúp hình dung các khoảng trống ở đầu / cuối và các chuỗi có độ dài bằng không.)
// Test 1: Test string from original question.
var test = "'string, duppi, du', 23, lala";
var a = CSVtoArray(test);
/* Array hes 3 elements:
a[0] = {string, duppi, du}
a[1] = {23}
a[2] = {lala} */
// Test 2: Empty CSV string.
var test = "";
var a = CSVtoArray(test);
/* Array hes 0 elements: */
// Test 3: CSV string with two empty values.
var test = ",";
var a = CSVtoArray(test);
/* Array hes 2 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 hes 3 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 hes 3 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 hes 8 elements:
a[0] = {one}
a[1] = {two}
a[2] = {}
a[3] = { four}
a[4] = {}
a[5] = {six }
a[6] = { seven }
a[7] = {} */
Ghi chú bổ sung:
Giải pháp này yêu cầu chuỗi CSV phải "hợp lệ". Ví dụ: các giá trị không được trích dẫn có thể không chứa dấu gạch chéo ngược hoặc dấu ngoặc kép, ví dụ: chuỗi CSV sau KHÔNG hợp lệ:
var invalid1 = "one, that's me!, escaped \, comma"
Đây không thực sự là một giới hạn vì bất kỳ chuỗi con nào cũng có thể được biểu diễn dưới dạng giá trị trích dẫn đơn hoặc kép. Cũng lưu ý rằng giải pháp này chỉ đại diện cho một định nghĩa khả thi cho: "Các giá trị được phân tách bằng dấu phẩy".
Chỉnh sửa: 2014-05-19: Đã thêm tuyên bố từ chối trách nhiệm.
Chỉnh sửa: 2014-12-01: Đã chuyển tuyên bố từ chối trách nhiệm lên đầu.