diff --git a/theodolite/src/main/kotlin/rocks/theodolite/core/IOHandler.kt b/theodolite/src/main/kotlin/rocks/theodolite/core/IOHandler.kt index 4d2cab0da938b18950def8cfb5cc6f104e110125..e70779afb34c4e7cecd561a2c4d64b09c9933ad5 100644 --- a/theodolite/src/main/kotlin/rocks/theodolite/core/IOHandler.kt +++ b/theodolite/src/main/kotlin/rocks/theodolite/core/IOHandler.kt @@ -64,20 +64,46 @@ class IOHandler { * Write to CSV file * * @param fileURL the URL of the file - * @param data the data to write in the file, as list of list, each subList corresponds to a row in the CSV file - * @param columns columns of the CSV file + * @param data the data to write in the csv, as list of list, + * each sublist corresponds to a row in the CSV file + * @param columns name of the columns */ fun writeToCSVFile(fileURL: String, data: List<List<String>>, columns: List<String>) { val outputFile = File("$fileURL.csv") PrintWriter(outputFile).use { pw -> - pw.println(columns.joinToString(separator = ",")) - data.forEach { - pw.println(it.joinToString(separator = ",")) + + val writeColumns = addQuotationMarks(columns) + pw.println(writeColumns.joinToString(separator = ",")) + + data.forEach{ row -> + val writeRow = addQuotationMarks(row) + pw.println(writeRow.joinToString(separator = ",")) } } logger.info { "Wrote CSV file: $fileURL to ${outputFile.absolutePath}." } } + /** + * For a list of Strings: + * - adds additional quotation mark to existing one + * - adds quotation marks around entries that contain a comma + */ + private fun addQuotationMarks(stringList: List<String> ): List<String> { + val stringMutableList = stringList.toMutableList() + stringMutableList.forEachIndexed { index, entry -> + // add additional quotation marks to escape them in csv + if (entry.contains("\"")){ + stringMutableList[index] = stringMutableList[index].replace('"'+"", "\"" + '"') + } + + // add quotation marks around entries that contain a comma + if (entry.contains(",")){ + stringMutableList[index] = '"' + stringMutableList[index] + '"' + } + } + return stringMutableList + } + /** * Write to text file * diff --git a/theodolite/src/test/kotlin/rocks/theodolite/core/IOHandlerTest.kt b/theodolite/src/test/kotlin/rocks/theodolite/core/IOHandlerTest.kt index 65e84d7dd37eb5b68f77bc2d47d212db2f720a90..e54bf7851b195927f69666caa2fd3b33fb3673d7 100644 --- a/theodolite/src/test/kotlin/rocks/theodolite/core/IOHandlerTest.kt +++ b/theodolite/src/test/kotlin/rocks/theodolite/core/IOHandlerTest.kt @@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test import org.junit.rules.TemporaryFolder import org.junitpioneer.jupiter.ClearEnvironmentVariable import org.junitpioneer.jupiter.SetEnvironmentVariable +import java.util.stream.Collectors const val FOLDER_URL = "Test-Folder" @@ -42,12 +43,13 @@ internal class IOHandlerTest { temporaryFolder.create() val folder = temporaryFolder.newFolder(FOLDER_URL) + val columns = listOf("Fruit", "Color") + val testContent = listOf( listOf("apples", "red"), listOf("bananas", "yellow"), listOf("avocado", "brown") ) - val columns = listOf("Fruit", "Color") IOHandler().writeToCSVFile( fileURL = "${folder.absolutePath}/test-file", @@ -65,6 +67,49 @@ internal class IOHandlerTest { ) } + /** + * Tests if values with commas and quotation marks are surrounded with additional quotation marks. + */ + @Test + fun testWriteToCSVFileWithComma() { + temporaryFolder.create() + val folder = temporaryFolder.newFolder(FOLDER_URL) + + val columns = listOf("Fruit, Fruit2", "Color") + val expectedColumns = listOf("\"Fruit, Fruit2\"", "Color") + + val testContent = listOf( + listOf("apples, "+ '"' + "paprika" + '"', "red"), + listOf("bananas, pineapple", "yellow"), + listOf("avocado, coconut", "brown") + ) + + val expectedContent = listOf( + listOf("\"apples, " + '"' + '"' + "paprika" + '"' + '"' + '"', "red"), + listOf("\"bananas, pineapple\"", "yellow"), + listOf("\"avocado, coconut\"", "brown") + ) + + IOHandler().writeToCSVFile( + fileURL = "${folder.absolutePath}/test-file", + data = testContent, + columns = columns + ) + + // construct string from the columns + var expected = expectedColumns.stream().collect(Collectors.joining(",")) + + // add values from the expectedContent to expected string + expectedContent.forEach{ + expected += "\n" + it.joinToString(separator = ",") + } + + assertEquals( + expected, + IOHandler().readFileAsString("${folder.absolutePath}/test-file.csv") + ) + } + @Test fun testWriteToJSONFile() { temporaryFolder.create()