fix: skip commas between quotes

This commit is contained in:
Chesterkxng
2025-04-07 02:41:20 +02:00
parent adf72108c6
commit cfc59f3ae0
2 changed files with 73 additions and 7 deletions

View File

@@ -50,7 +50,8 @@ export function main(input: string, options: InitialValuesType): string {
true, true,
options.commentCharacter, options.commentCharacter,
options.emptyLines, options.emptyLines,
options.csvSeparator options.csvSeparator,
options.quoteCharacter
); );
rows.forEach((row) => { rows.forEach((row) => {
@@ -60,7 +61,12 @@ export function main(input: string, options: InitialValuesType): string {
}); });
if (options.headerRow) { if (options.headerRow) {
const headerRow = getCsvHeaders(input, options.csvSeparator); const headerRow = getCsvHeaders(
input,
options.csvSeparator,
options.quoteCharacter,
options.commentCharacter
);
headerRow.forEach((header, headerIndex) => { headerRow.forEach((header, headerIndex) => {
headerRow[headerIndex] = unquoteIfQuoted(header, options.quoteCharacter); headerRow[headerIndex] = unquoteIfQuoted(header, options.quoteCharacter);
}); });

View File

@@ -1,3 +1,41 @@
/**
* Splits a CSV line into string[], handling quoted string.
* @param {string} input - The CSV input string.
* @param {string} delimiter - The character used to split csvlines.
* @param {string} quoteChar - The character used to quotes csv values.
* @returns {string[][]} - The CSV line as a 1D array.
*/
function splitCsvLine(
line: string,
delimiter: string = ',',
quoteChar: string = '"'
): string[] {
const result: string[] = [];
let current = '';
let inQuotes = false;
for (let i = 0; i < line.length; i++) {
const char = line[i];
const nextChar = line[i + 1];
if (char === quoteChar) {
if (inQuotes && nextChar === quoteChar) {
current += quoteChar;
i++; // Skip the escaped quote
} else {
inQuotes = !inQuotes;
}
} else if (char === delimiter && !inQuotes) {
result.push(current.trim());
current = '';
} else {
current += char;
}
}
result.push(current.trim());
return result;
}
/** /**
* Splits a CSV string into rows, skipping any blank lines. * Splits a CSV string into rows, skipping any blank lines.
* @param {string} input - The CSV input string. * @param {string} input - The CSV input string.
@@ -9,9 +47,12 @@ export function splitCsv(
deleteComment: boolean, deleteComment: boolean,
commentCharacter: string, commentCharacter: string,
deleteEmptyLines: boolean, deleteEmptyLines: boolean,
delimiter: string = ',' delimiter: string = ',',
quoteChar: string = '"'
): string[][] { ): string[][] {
let rows = input.split('\n').map((row) => row.split(delimiter)); let rows = input
.split('\n')
.map((row) => splitCsvLine(row, delimiter, quoteChar));
// Remove comments if deleteComment is true // Remove comments if deleteComment is true
if (deleteComment && commentCharacter) { if (deleteComment && commentCharacter) {
@@ -30,12 +71,31 @@ export function splitCsv(
* get the headers from a CSV string . * get the headers from a CSV string .
* @param {string} input - The CSV input string. * @param {string} input - The CSV input string.
* @param {string} csvSeparator - The character used to separate values in the CSV. * @param {string} csvSeparator - The character used to separate values in the CSV.
* @param {string} quoteChar - The character used to quotes csv values.
* @param {string} commentCharacter - The character used to denote comments.
* @returns {string[]} - The CSV header as a 1D array. * @returns {string[]} - The CSV header as a 1D array.
*/ */
export function getCsvHeaders( export function getCsvHeaders(
csvString: string, csvString: string,
csvSeparator: string = ',' csvSeparator: string = ',',
quoteChar: string = '"',
commentCharacter?: string
): string[] { ): string[] {
const rows = csvString.split('\n').map((row) => row.split(csvSeparator)); const lines = csvString.split('\n');
return rows.length > 0 ? rows[0].map((header) => header.trim()) : [];
for (const line of lines) {
const trimmed = line.trim();
if (
trimmed === '' ||
(commentCharacter && trimmed.startsWith(commentCharacter))
) {
continue; // skip empty or commented lines
}
const headerLine = splitCsvLine(trimmed, csvSeparator, quoteChar);
return headerLine.map((h) => h.replace(/^\uFEFF/, '').trim());
}
return [];
} }