diff --git a/src/pages/tools/csv/change-csv-separator/change-csv-separator.service.test.ts b/src/pages/tools/csv/change-csv-separator/change-csv-separator.service.test.ts new file mode 100644 index 0000000..dafa9b0 --- /dev/null +++ b/src/pages/tools/csv/change-csv-separator/change-csv-separator.service.test.ts @@ -0,0 +1,125 @@ +import { expect, describe, it } from 'vitest'; +import { changeCsvSeparator } from './service'; +import { InitialValuesType } from './types'; + +describe('changeCsvSeparator', () => { + it('should change the separator from comma to semicolon', () => { + const inputCsv = 'name,age,city\nJohn,30,New York'; + const options: InitialValuesType = { + inputSeparator: ',', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: false, + outputSeparator: ';', + outputQuoteAll: false, + OutputQuoteCharacter: '"' + }; + const result = changeCsvSeparator(inputCsv, options); + expect(result).toBe('name;age;city\nJohn;30;New York'); + }); + + it('should handle empty input gracefully', () => { + const inputCsv = ''; + const options: InitialValuesType = { + inputSeparator: ',', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: false, + outputSeparator: ';', + outputQuoteAll: false, + OutputQuoteCharacter: '"' + }; + const result = changeCsvSeparator(inputCsv, options); + expect(result).toBe(''); + }); + + it('should not modify the CSV if the separator is already correct', () => { + const inputCsv = 'name;age;city\nJohn;30;New York'; + const options: InitialValuesType = { + inputSeparator: ';', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: false, + outputSeparator: ';', + outputQuoteAll: false, + OutputQuoteCharacter: '"' + }; + const result = changeCsvSeparator(inputCsv, options); + expect(result).toBe(inputCsv); + }); + + it('should handle custom separators', () => { + const inputCsv = 'name|age|city\nJohn|30|New York'; + const options: InitialValuesType = { + inputSeparator: '|', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: false, + outputSeparator: ';', + outputQuoteAll: false, + OutputQuoteCharacter: '"' + }; + const result = changeCsvSeparator(inputCsv, options); + expect(result).toBe('name;age;city\nJohn;30;New York'); + }); + + it('should quote all output values', () => { + const inputCsv = 'name|age|city\nJohn|30|New York'; + const options: InitialValuesType = { + inputSeparator: '|', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: false, + outputSeparator: ';', + outputQuoteAll: true, + OutputQuoteCharacter: '"' + }; + const result = changeCsvSeparator(inputCsv, options); + expect(result).toBe('"name";"age";"city"\n"John";"30";"New York"'); + }); + + it('should remove quotes from input values', () => { + const inputCsv = '"name"|"age"|"city"\n"John"|"30"|"New York"'; + const options: InitialValuesType = { + inputSeparator: '|', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: false, + outputSeparator: ';', + outputQuoteAll: false, + OutputQuoteCharacter: '"' + }; + const result = changeCsvSeparator(inputCsv, options); + expect(result).toBe('name;age;city\nJohn;30;New York'); + }); + + it('should handle emptylines', () => { + const inputCsv = '"name"|"age"|"city"\n\n"John"|"30"|"New York"'; + const options: InitialValuesType = { + inputSeparator: '|', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: true, + outputSeparator: ';', + outputQuoteAll: false, + OutputQuoteCharacter: '"' + }; + const result = changeCsvSeparator(inputCsv, options); + expect(result).toBe('name;age;city\nJohn;30;New York'); + }); + + it('should handle emptylines', () => { + const inputCsv = '"name"|"age"|"city"\n\n"John"|"30"|"New York"'; + const options: InitialValuesType = { + inputSeparator: '|', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: true, + outputSeparator: ';', + outputQuoteAll: false, + OutputQuoteCharacter: '"' + }; + const result = changeCsvSeparator(inputCsv, options); + expect(result).toBe('name;age;city\nJohn;30;New York'); + }); +}); diff --git a/src/pages/tools/csv/change-csv-separator/index.tsx b/src/pages/tools/csv/change-csv-separator/index.tsx new file mode 100644 index 0000000..ed79692 --- /dev/null +++ b/src/pages/tools/csv/change-csv-separator/index.tsx @@ -0,0 +1,213 @@ +import { Box } from '@mui/material'; +import React, { useState } from 'react'; +import ToolContent from '@components/ToolContent'; +import { ToolComponentProps } from '@tools/defineTool'; +import ToolTextInput from '@components/input/ToolTextInput'; +import ToolTextResult from '@components/result/ToolTextResult'; +import { GetGroupsType } from '@components/options/ToolOptions'; +import { CardExampleType } from '@components/examples/ToolExamples'; +import { changeCsvSeparator } from './service'; +import { InitialValuesType } from './types'; +import TextFieldWithDesc from '@components/options/TextFieldWithDesc'; +import CheckboxWithDesc from '@components/options/CheckboxWithDesc'; + +const initialValues: InitialValuesType = { + inputSeparator: ',', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: false, + outputSeparator: ';', + outputQuoteAll: false, + OutputQuoteCharacter: '"' +}; + +const exampleCards: CardExampleType[] = [ + { + title: 'Change the CSV Delimiter to a Semicolon', + description: + 'In this example, we change the column separator to the semicolon separator in a CSV file containing data about countries, their populations, and population densities. As you can see, the input CSV file uses the standard commas as separators. After specifying this delimiter in the source CSV options, we set a new CSV delimiter for the output file to a semicolon, resulting in a new CSV file that now uses semicolons ";" in the output. Such CSV files with semicolons are called SSV files (semicolon-separated values files)', + sampleText: `country,population,density +China,1412,152 +India,1408,428 +United States,331,37 +Indonesia,273,145 +Pakistan,231,232 +Brazil,214,26`, + sampleResult: `country;population;density +China;1412;152 +India;1408;428 +United States;331;37 +Indonesia;273;145 +Pakistan;231;232 +Brazil;214;26`, + sampleOptions: { + inputSeparator: ',', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: false, + outputSeparator: ';', + outputQuoteAll: false, + OutputQuoteCharacter: '"' + } + }, + { + title: 'Restore a CSV File to the Standard Format', + description: + 'In this example, a data scientist working with flowers was given an unusual CSV file that uses the vertical bar symbol as the field separator (such files are called PSV files – pipe-separated values files). To transform the file back to the standard comma-separated values (CSV) file, in the options, she set the input delimiter to "|" and the new delimiter to ",". She also wrapped the output fields in single quotes, enabled the option to remove empty lines from the input, and discarded comment lines starting with the "#" symbol.', + sampleText: `species|height|days|temperature + +Sunflower|50cm|30|25°C +Rose|40cm|25|22°C +Tulip|35cm|20|18°C +Daffodil|30cm|15|20°C + +Lily|45cm|28|23°C +#pumpkin +Brazil,214,26`, + sampleResult: `'species','height','days','temperature' +'Sunflower','50cm','30','25°C' +'Rose','40cm','25','22°C' +'Tulip','35cm','20','18°C' +'Daffodil','30cm','15','20°C' +'Lily','45cm','28','23°C'`, + sampleOptions: { + inputSeparator: '|', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: true, + outputSeparator: ',', + outputQuoteAll: true, + OutputQuoteCharacter: "'" + } + }, + { + title: 'Plants vs. Zombies CSV', + description: + 'In this example, we import CSV data with zombie characters from the game Plants vs. Zombies. The data includes zombies names, the level at which they first appear in the game, their health, damage, and speed. The data follows the standard CSV format, with commas serving as field separators. To change the readability of the file, we replace the usual comma delimiter with a slash symbol, creating a slash-separated values file.', + sampleText: `zombie_name,first_seen,health,damage,speed +Normal Zombie,Level 1-1,181,100,4.7 +Conehead Zombie,Level 1-3,551,100,4.7 +Buckethead Zombi,Level 1-8,1281,100,4.7 +Newspaper Zombie,Level 2-1,331,100,4.7 +Football Zombie,Level 2-6,1581,100,2.5 +Dancing Zombie,Level 2-8,335,100,1.5 +Zomboni,Level 3-6,1151,Instant-kill,varies +Catapult Zombie,Level 5-6,651,75,2.5 +Gargantuar,Level 5-8,3000,Instant-kill,4.7`, + sampleResult: `zombie_name/first_seen/health/damage/speed +Normal Zombie/Level 1-1/181/100/4.7 +Conehead Zombie/Level 1-3/551/100/4.7 +Buckethead Zombi/Level 1-8/1281/100/4.7 +Newspaper Zombie/Level 2-1/331/100/4.7 +Football Zombie/Level 2-6/1581/100/2.5 +Dancing Zombie/Level 2-8/335/100/1.5 +Zomboni/Level 3-6/1151/Instant-kill/varies +Catapult Zombie/Level 5-6/651/75/2.5 +Gargantuar/Level 5-8/3000/Instant-kill/4.7`, + sampleOptions: { + inputSeparator: ',', + inputQuoteCharacter: '"', + commentCharacter: '#', + emptyLines: true, + outputSeparator: '/', + outputQuoteAll: false, + OutputQuoteCharacter: "'" + } + } +]; +export default function ChangeCsvDelimiter({ + title, + longDescription +}: ToolComponentProps) { + const [input, setInput] = useState(''); + const [result, setResult] = useState(''); + + const compute = (values: InitialValuesType, input: string) => { + setResult(changeCsvSeparator(input, values)); + }; + + const getGroups: GetGroupsType | null = ({ + values, + updateField + }) => [ + { + title: 'Adjust CSV input options', + component: ( + + updateField('inputSeparator', val)} + description={ + 'Enter the character used to delimit columns in the CSV input file.' + } + /> + updateField('inputQuoteCharacter', val)} + description={ + 'Enter the quote character used to quote the CSV input fields.' + } + /> + updateField('commentCharacter', val)} + description={ + 'Enter the character indicating the start of a comment line. Lines starting with this symbol will be skipped.' + } + /> + updateField('emptyLines', value)} + title="Delete Lines with No Data" + description="Remove empty lines from CSV input file." + /> + + ) + }, + { + title: 'Output options', + component: ( + + updateField('outputSeparator', val)} + description={ + 'Enter the character used to delimit columns in the CSV output file.' + } + /> + updateField('outputQuoteAll', value)} + title="Quote All Output Fields" + description="Wrap all fields of the output CSV file in quotes" + /> + {values.outputQuoteAll && ( + updateField('OutputQuoteCharacter', val)} + description={ + 'Enter the quote character used to quote the CSV output fields.' + } + /> + )} + + ) + } + ]; + return ( + + } + resultComponent={} + initialValues={initialValues} + exampleCards={exampleCards} + getGroups={getGroups} + setInput={setInput} + compute={compute} + toolInfo={{ title: `What is a ${title}?`, description: longDescription }} + /> + ); +} diff --git a/src/pages/tools/csv/change-csv-separator/meta.ts b/src/pages/tools/csv/change-csv-separator/meta.ts new file mode 100644 index 0000000..3b4a832 --- /dev/null +++ b/src/pages/tools/csv/change-csv-separator/meta.ts @@ -0,0 +1,15 @@ +import { defineTool } from '@tools/defineTool'; +import { lazy } from 'react'; + +export const tool = defineTool('csv', { + name: 'Change csv separator', + path: 'change-csv-separator', + icon: 'material-symbols:split-scene-rounded', + description: + 'Just upload your CSV file in the form below and it will automatically get a new column delimiter character. In the tool options, you can specify which delimiter and quote characters are used in the source CSV file and customize the desired delimiter and quote characters for the output CSV. You can also filter the input CSV before the conversion process and skip blank lines and comment lines.', + shortDescription: 'Quickly change the CSV column delimiter to a new symbol.', + keywords: ['change', 'csv', 'sepa rator'], + longDescription: + 'This tool changes the field separator in CSV (Comma Separated Values) files. This is useful because different programs may use different default separators. While a comma is the most common separator in CSV files, some programs require files to be tab-separated (TSV), semicolon-separated (SSV), pipe-separated (PSV), or have another separation symbol. The default comma may not be so convenient as a delimiter in CSV files because commas are frequently present within fields. In such cases, it can be difficult and confusing to distinguish between commas as delimiters and commas as punctuation symbols. By replacing the comma with another delimiter, you can convert the file into a more easily readable and parsable format. In the options section of this tool, you can configure both the input and output CSV file formats. For the input CSV, you can specify its current delimiter (by default, it is a comma) and also indicate the quotation mark character used to wrap fields. For the output CSV, you can set a new delimiter, choose a new quotation mark character, and optionally enclose all the fields in quotes. Additionally, you have the option to remove empty lines from the input CSV and eliminate comment lines that start with a specified character (usually a hash "#" or double slashes "//"). Csv-abulous!', + component: lazy(() => import('./index')) +}); diff --git a/src/pages/tools/csv/change-csv-separator/service.ts b/src/pages/tools/csv/change-csv-separator/service.ts new file mode 100644 index 0000000..d4e19df --- /dev/null +++ b/src/pages/tools/csv/change-csv-separator/service.ts @@ -0,0 +1,31 @@ +import { InitialValuesType } from './types'; +import { splitCsv } from '@utils/csv'; + +export function changeCsvSeparator( + input: string, + options: InitialValuesType +): string { + if (!input) return ''; + + const rows = splitCsv( + input, + true, + options.commentCharacter, + options.emptyLines, + options.inputSeparator, + options.inputQuoteCharacter + ); + + return rows + .map((row) => { + return row + .map((cell) => { + if (options.outputQuoteAll) { + return `${options.OutputQuoteCharacter}${cell}${options.OutputQuoteCharacter}`; + } + return cell; + }) + .join(options.outputSeparator); + }) + .join('\n'); +} diff --git a/src/pages/tools/csv/change-csv-separator/types.ts b/src/pages/tools/csv/change-csv-separator/types.ts new file mode 100644 index 0000000..91bd6c0 --- /dev/null +++ b/src/pages/tools/csv/change-csv-separator/types.ts @@ -0,0 +1,9 @@ +export type InitialValuesType = { + inputSeparator: string; + inputQuoteCharacter: string; + commentCharacter: string; + emptyLines: boolean; + outputSeparator: string; + outputQuoteAll: boolean; + OutputQuoteCharacter: string; +}; diff --git a/src/pages/tools/csv/find-incomplete-csv-records/index.tsx b/src/pages/tools/csv/find-incomplete-csv-records/index.tsx new file mode 100644 index 0000000..1831451 --- /dev/null +++ b/src/pages/tools/csv/find-incomplete-csv-records/index.tsx @@ -0,0 +1,198 @@ +import { Box } from '@mui/material'; +import React, { useState } from 'react'; +import ToolContent from '@components/ToolContent'; +import { ToolComponentProps } from '@tools/defineTool'; +import ToolTextInput from '@components/input/ToolTextInput'; +import ToolTextResult from '@components/result/ToolTextResult'; +import { GetGroupsType } from '@components/options/ToolOptions'; +import { CardExampleType } from '@components/examples/ToolExamples'; +import { findIncompleteCsvRecords } from './service'; +import { InitialValuesType } from './types'; +import TextFieldWithDesc from '@components/options/TextFieldWithDesc'; +import CheckboxWithDesc from '@components/options/CheckboxWithDesc'; + +const initialValues: InitialValuesType = { + csvSeparator: ',', + quoteCharacter: '"', + commentCharacter: '#', + emptyLines: true, + emptyValues: true, + messageLimit: false, + messageNumber: 10 +}; + +const exampleCards: CardExampleType[] = [ + { + title: 'CSV Completeness Check', + description: + 'In this example, we upload a simple CSV file containing names, surnames, and dates of birth. The tool analyzes the data and displays a green "Complete CSV" badge as it finds that there are no missing values or empty records. To say it differently, this check confirms that all rows and columns have the expected number of values in the data and the file is ready for use in any software that imports CSV files without hiccups.', + sampleText: `name,surname,dob +John,Warner,1990-05-15 +Lily,Meadows,1985-12-20 +Jaime,Crane,1993-01-23 +Jeri,Carroll,2000-11-07 +Simon,Harper,2013-04-10`, + sampleResult: `The Csv input is complete.`, + sampleOptions: { + csvSeparator: ',', + quoteCharacter: '"', + commentCharacter: '#', + emptyLines: true, + emptyValues: true, + messageLimit: false, + messageNumber: 10 + } + }, + { + title: 'Find Missing Fields in Broken CSV', + description: + 'In this example, we find the missing fields in a CSV file containing city names, time zones, and standard time information. As a result of the analysis, we see a red badge in the output and a text list of missing values in the dataset. The file has missing values on two rows: row 3 lacks standard time data (column 3), and row 5 lacks time zone and standard time data (columns 2 and 3).', + sampleText: `City,Time Zone,Standard Time +London,UTC+00:00,GMT +Chicago,UTC-06:00 +Tokyo,UTC+09:00,JST +Sydney +Berlin,UTC+01:00,CET`, + sampleResult: `Title: Found missing column(s) on line 3 +Message: Line 3 has 1 missing column(s). + +Title: Found missing column(s) on line 5 +Message: Line 5 has 2 missing column(s).`, + sampleOptions: { + csvSeparator: ',', + quoteCharacter: '"', + commentCharacter: '#', + emptyLines: true, + emptyValues: false, + messageLimit: true, + messageNumber: 10 + } + }, + { + title: 'Detect Empty and Missing Values', + description: + 'This example checks a data file containing information astronomical data about constellations. Not only does it find incomplete records but also detects all empty fields by activating the "Find Empty Values" checkbox. The empty fields are those that have zero length or contain just whitespace. Such fields contain no information. Additionally, since this file uses semicolons instead of commas for separators, we specify the ";" symbol in the options to make the program work with SSV (Semicolon-Separated Values) data. As a result, the program identifies three empty fields and one row with missing data.', + sampleText: `Abbreviation;Constellation;Main stars + +Cas;Cassiopeia;5 +Cep;Cepheus;7 +;Andromeda;16 + +Cyg;; +Del;Delphinus`, + sampleResult: `Title: Found missing values on line 4 +Message: Empty values on line 4: column 1. + +Title: Found missing values on line 5 +Message: Empty values on line 5: column 2, column 3. + +Title: Found missing column(s) on line 6 +Message: Line 6 has 1 missing column(s).`, + sampleOptions: { + csvSeparator: ';', + quoteCharacter: '"', + commentCharacter: '#', + emptyLines: true, + emptyValues: true, + messageLimit: true, + messageNumber: 10 + } + } +]; +export default function FindIncompleteCsvRecords({ + title, + longDescription +}: ToolComponentProps) { + const [input, setInput] = useState(''); + const [result, setResult] = useState(''); + + const compute = (values: InitialValuesType, input: string) => { + setResult(findIncompleteCsvRecords(input, values)); + }; + + const getGroups: GetGroupsType | null = ({ + values, + updateField + }) => [ + { + title: 'Csv input Options', + component: ( + + updateField('csvSeparator', val)} + description={ + 'Enter the character used to delimit columns in the CSV input file.' + } + /> + updateField('quoteCharacter', val)} + description={ + 'Enter the quote character used to quote the CSV input fields.' + } + /> + updateField('commentCharacter', val)} + description={ + 'Enter the character indicating the start of a comment line. Lines starting with this symbol will be skipped.' + } + /> + + ) + }, + { + title: 'Checking Options', + component: ( + + updateField('emptyLines', value)} + title="Delete Lines with No Data" + description="Remove empty lines from CSV input file." + /> + + updateField('emptyValues', value)} + title="Find Empty Values" + description="Display a message about CSV fields that are empty (These are not missing fields but fields that contain nothing)." + /> + + updateField('messageLimit', value)} + title="Limit number of messages" + /> + + {values.messageLimit && ( + updateField('messageNumber', Number(val))} + type="number" + inputProps={{ min: 1 }} + description={'Set the limit of number of messages in the output.'} + /> + )} + + ) + } + ]; + return ( + + } + resultComponent={} + initialValues={initialValues} + exampleCards={exampleCards} + getGroups={getGroups} + setInput={setInput} + compute={compute} + toolInfo={{ title: `What is a ${title}?`, description: longDescription }} + /> + ); +} diff --git a/src/pages/tools/csv/find-incomplete-csv-records/meta.ts b/src/pages/tools/csv/find-incomplete-csv-records/meta.ts new file mode 100644 index 0000000..d3e9752 --- /dev/null +++ b/src/pages/tools/csv/find-incomplete-csv-records/meta.ts @@ -0,0 +1,16 @@ +import { defineTool } from '@tools/defineTool'; +import { lazy } from 'react'; + +export const tool = defineTool('csv', { + name: 'Find incomplete csv records', + path: 'find-incomplete-csv-records', + icon: 'tdesign:search-error', + description: + 'Just upload your CSV file in the form below and this tool will automatically check if none of the rows or columns are missing values. In the tool options, you can adjust the input file format (specify the delimiter, quote character, and comment character). Additionally, you can enable checking for empty values, skip empty lines, and set a limit on the number of error messages in the output.', + shortDescription: + 'Quickly find rows and columns in CSV that are missing values.', + keywords: ['find', 'incomplete', 'csv', 'records'], + longDescription: + 'This tool checks the completeness of CSV (Comma Separated Values) files and identifies incomplete records within the data. It finds rows and columns where one or more values are missing and displays their positions in the output so that you can quickly find and fix your CSV file. A valid CSV file has the same number of values (fields) in all rows and the same number of values (fields) in all columns. If the CSV you load in this tool is complete, the program will notify you with a green badge. If at least one value is missing in any row or column, the program will show a red badge and indicate the exact location of the missing value. If the CSV file has a field with no characters in it, then such a field is called an empty field. It is not a missing field, just empty as it contains nothing. You can activate the "Find Empty Values" checkbox in the options to identify all such fields in the CSV. If the file contains empty lines, you can ignore them with the "Skip Empty Lines" option or check them for completeness along with other lines. You can also configure the delimiter, quote, and comment characters in the options. This allows you to adapt to other file formats besides CSV, such as TSV (Tab Separated Values), SSV (Semicolon Separated Values), or PSV (Pipe Separated Values). If the file has too many incomplete or empty records, you can set a limit on the output messages to display, for example, 5, 10, or 20 messages. If you want to quickly fill in the missing data with default values, you can use our Fill Incomplete CSV Records tool. Csv-abulous!', + component: lazy(() => import('./index')) +}); diff --git a/src/pages/tools/csv/find-incomplete-csv-records/service.ts b/src/pages/tools/csv/find-incomplete-csv-records/service.ts new file mode 100644 index 0000000..0fd5678 --- /dev/null +++ b/src/pages/tools/csv/find-incomplete-csv-records/service.ts @@ -0,0 +1,80 @@ +import { InitialValuesType } from './types'; +import { splitCsv } from '@utils/csv'; + +function generateMessage( + row: string[], + lineIndex: number, + maxLength: number, + emptyLines: boolean, + emptyValues: boolean +) { + const lineNumber = lineIndex + 1; + // check if empty lines are allowed + if (!emptyLines && row.length === 1 && row[0] === '') + return { title: 'Missing Line', message: `Line ${lineNumber} is empty.` }; + + // if row legth is less than maxLength it means that there are missing columns + if (row.length < maxLength) + return { + title: `Found missing column(s) on line ${lineNumber}`, + message: `Line ${lineNumber} has ${ + maxLength - row.length + } missing column(s).` + }; + + // if row length is equal to maxLength we should check if there are empty values + if (row.length == maxLength && emptyValues) { + let missingValues = false; + let message = `Empty values on line ${lineNumber}: `; + row.forEach((cell, index) => { + if (cell.trim() === '') { + missingValues = true; + message += `column ${index + 1}, `; + } + }); + if (missingValues) + return { + title: `Found missing values on line ${lineNumber}`, + message: message.slice(0, -2) + '.' + }; + } + + return null; +} +export function findIncompleteCsvRecords( + input: string, + options: InitialValuesType +): string { + if (!input) return ''; + + if (options.messageLimit && options.messageNumber <= 0) + throw new Error('Message number must be greater than 0'); + + const rows = splitCsv( + input, + true, + options.commentCharacter, + options.emptyLines, + options.csvSeparator, + options.quoteCharacter + ); + const maxLength = Math.max(...rows.map((row) => row.length)); + const messages = rows + .map((row, index) => + generateMessage( + row, + index, + maxLength, + options.emptyLines, + options.emptyValues + ) + ) + .filter(Boolean) + .map((msg) => `Title: ${msg!.title}\nMessage: ${msg!.message}`); + + return messages.length > 0 + ? options.messageLimit + ? messages.slice(0, options.messageNumber).join('\n\n') + : messages.join('\n\n') + : 'The Csv input is complete.'; +} diff --git a/src/pages/tools/csv/find-incomplete-csv-records/types.ts b/src/pages/tools/csv/find-incomplete-csv-records/types.ts new file mode 100644 index 0000000..b5a8e6c --- /dev/null +++ b/src/pages/tools/csv/find-incomplete-csv-records/types.ts @@ -0,0 +1,9 @@ +export type InitialValuesType = { + csvSeparator: string; + quoteCharacter: string; + commentCharacter: string; + emptyLines: boolean; + emptyValues: boolean; + messageLimit: boolean; + messageNumber: number; +}; diff --git a/src/pages/tools/csv/index.ts b/src/pages/tools/csv/index.ts index 3c7a65c..78ae56b 100644 --- a/src/pages/tools/csv/index.ts +++ b/src/pages/tools/csv/index.ts @@ -1,3 +1,5 @@ +import { tool as findIncompleteCsvRecords } from './find-incomplete-csv-records/meta'; +import { tool as ChangeCsvDelimiter } from './change-csv-separator/meta'; import { tool as csvToYaml } from './csv-to-yaml/meta'; import { tool as csvToJson } from './csv-to-json/meta'; import { tool as csvToXml } from './csv-to-xml/meta'; @@ -11,5 +13,7 @@ export const csvTools = [ csvToRowsColumns, csvToTsv, swapCsvColumns, - csvToYaml + csvToYaml, + ChangeCsvDelimiter, + findIncompleteCsvRecords ];