ข้อจำกัดความรับผิดชอบ
อัปเดต 2014-12-01: คำตอบด้านล่างใช้ได้กับรูปแบบ CSV ที่เฉพาะเจาะจงรูปแบบเดียวเท่านั้น ตามที่ DGระบุไว้อย่างถูกต้องในความคิดเห็นโซลูชันนี้ไม่สอดคล้องกับคำจำกัดความ RFC 4180 ของ CSV และยังไม่พอดีกับรูปแบบ Microsoft Excel โซลูชันนี้แสดงให้เห็นว่าเราสามารถแยกวิเคราะห์บรรทัด CSV หนึ่งบรรทัด (ที่ไม่ได้มาตรฐาน) ซึ่งมีการผสมของประเภทสตริงโดยที่สตริงอาจมีเครื่องหมายอัญประกาศและเครื่องหมายจุลภาคที่ใช้ Escape
โซลูชัน CSV ที่ไม่ได้มาตรฐาน
ดังที่austincheney ชี้ให้เห็นอย่างถูกต้องคุณจำเป็นต้องแยกวิเคราะห์สตริงตั้งแต่ต้นจนจบหากคุณต้องการจัดการสตริงที่ยกมาอย่างถูกต้องซึ่งอาจมีอักขระที่ใช้ Escape นอกจากนี้ OP ไม่ได้กำหนดอย่างชัดเจนว่า "สตริง CSV" คืออะไร ก่อนอื่นเราต้องกำหนดสิ่งที่เป็นสตริง CSV ที่ถูกต้องและแต่ละค่า
ระบุ: คำจำกัดความ "สตริง CSV"
เพื่อจุดประสงค์ของการสนทนานี้ "สตริง CSV" ประกอบด้วยค่าศูนย์หรือมากกว่าโดยที่ค่าหลายค่าจะถูกคั่นด้วยลูกน้ำ แต่ละค่าอาจประกอบด้วย:
- สตริงที่มีเครื่องหมายอัญประกาศคู่ (อาจมีเครื่องหมายคำพูดเดี่ยวที่ไม่ใช้ Escape)
- สตริงคำพูดเดี่ยว (อาจมีเครื่องหมายคำพูดคู่ที่ไม่ใช้ Escape)
- สตริงที่ไม่มีเครื่องหมายคำพูด(ต้องไม่มีเครื่องหมายคำพูดลูกน้ำหรือแบ็กสแลช)
- ค่าว่าง (ค่าช่องว่างทั้งหมดถือเป็นค่าว่าง)
กฎ / หมายเหตุ:
- ค่าที่ยกมาอาจมีเครื่องหมายจุลภาค
'that\'s cool'
ค่าที่ยกมาอาจมีหนีอะไรเช่น
- ต้องใส่เครื่องหมายอัญประกาศจุลภาคหรือแบ็กสแลช
- ค่าที่มีช่องว่างนำหน้าหรือต่อท้ายต้องถูกยกมา
- แบ็กสแลชจะถูกลบออกจากทั้งหมด:
\'
ในค่าที่ยกมาเดียว
- แบ็กสแลชจะถูกลบออกจากทั้งหมด:
\"
ในค่าที่ยกมาสองครั้ง
- สตริงที่ไม่มีเครื่องหมายคำพูดจะถูกตัดออกจากช่องว่างที่นำหน้าและต่อท้าย
- ตัวคั่นลูกน้ำอาจมีช่องว่างที่อยู่ติดกัน (ซึ่งถูกละเว้น)
หา:
ฟังก์ชัน JavaScript ที่แปลงสตริง CSV ที่ถูกต้อง (ตามที่กำหนดไว้ด้านบน) เป็นอาร์เรย์ของค่าสตริง
วิธีการแก้:
นิพจน์ทั่วไปที่ใช้โดยโซลูชันนี้มีความซับซ้อน และ (IMHO) ทั้งหมดไม่น่ารำคาญแสดงออกปกติควรจะนำเสนอในโหมดฟรีระยะห่างที่มีจำนวนมากแสดงความคิดเห็นและการเยื้อง น่าเสียดายที่ JavaScript ไม่อนุญาตให้ใช้โหมดเว้นระยะห่าง ดังนั้นนิพจน์ทั่วไปที่ใช้โดยโซลูชันนี้จึงถูกนำเสนอครั้งแรกในไวยากรณ์ของนิพจน์ทั่วไปแบบเนทีฟ (แสดงโดยใช้r'''...'''
ไวยากรณ์สตริงดิบหลายบรรทัดที่มีประโยชน์ของ Python )
อันดับแรกนี่คือนิพจน์ทั่วไปที่ตรวจสอบว่าสตริง CVS ตรงตามข้อกำหนดข้างต้น:
นิพจน์ทั่วไปเพื่อตรวจสอบ "สตริง 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.
"""
โปรดสังเกตว่ามีค่ากรณีพิเศษค่าหนึ่งที่นิพจน์ทั่วไปนี้ไม่ตรงกันนั่นคือค่าสุดท้ายเมื่อค่านั้นว่างเปล่า พิเศษนี้"ว่างค่าสุดท้าย"กรณีที่มีการทดสอบและการจัดการโดยใช้ฟังก์ชัน JavaScript ซึ่งต่อไปนี้
ฟังก์ชัน JavaScript เพื่อแยกวิเคราะห์สตริง CSV:
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;
if (!re_valid.test(text)) return null;
var a = [];
text.replace(re_value,
function(m0, m1, m2, m3) {
if (m1 !== undefined) a.push(m1.replace(/\\'/g, "'"));
else if (m2 !== undefined) a.push(m2.replace(/\\"/g, '"'));
else if (m3 !== undefined) a.push(m3);
return '';
});
if (/,\s*$/.test(text)) a.push('');
return a;
};
ตัวอย่างอินพุตและเอาต์พุต:
ในตัวอย่างต่อไปนี้ใช้วงเล็บปีกกาเพื่อคั่น{result strings}
. (นี่คือการช่วยให้เห็นภาพช่องว่างนำหน้า / ต่อท้ายและสตริงที่มีความยาวเป็นศูนย์)
var test = "'string, duppi, du', 23, lala";
var a = CSVtoArray(test);
var test = "";
var a = CSVtoArray(test);
var test = ",";
var a = CSVtoArray(test);
var test = "'one','two with escaped \' single quote', 'three, with, commas'";
var a = CSVtoArray(test);
var test = '"one","two with escaped \" double quote", "three, with, commas"';
var a = CSVtoArray(test);
var test = " one , 'two' , , ' four' ,, 'six ', ' seven ' , ";
var a = CSVtoArray(test);
หมายเหตุเพิ่มเติม:
โซลูชันนี้ต้องการให้สตริง CSV "ถูกต้อง" ตัวอย่างเช่นค่าที่ไม่ได้ใส่เครื่องหมายคำพูดต้องไม่มีแบ็กสแลชหรือเครื่องหมายคำพูดเช่นสตริง CSV ต่อไปนี้ไม่ถูกต้อง:
var invalid1 = "one, that's me!, escaped \, comma"
นี่ไม่ใช่ข้อ จำกัด จริงๆเนื่องจากสตริงย่อยใด ๆ อาจแสดงเป็นค่าที่ยกมาเดี่ยวหรือคู่ก็ได้ โปรดทราบว่าโซลูชันนี้แสดงถึงคำจำกัดความที่เป็นไปได้เพียงคำเดียวสำหรับ "ค่าที่คั่นด้วยเครื่องหมายจุลภาค"
แก้ไขประวัติ
- 2014-05-19:เพิ่มข้อจำกัดความรับผิดชอบ
- 2014-12-01:ย้ายข้อจำกัดความรับผิดชอบไปด้านบน