patternMinor
Reading and parsing CSV files
Viewed 0 times
readingcsvfilesparsingand
Problem
This is my first real attempt at a Scala program. I come from a predominantly Java background, so I'd like to know if the program sticks to Scala conventions well.
Is it well readable or should it be formulated differently? To me, there is a lot of lines in the main function which doesn't quite bode right.
It is functioning and I can provide my JUnit tests to prove it. Not all tests pass as those dealing with whitespace are now different.
I didn't want to use any parsing library or support as that doesn't help me learn the core of the language.
```
package com.wesleyacheson
import scala.io.Source
import scala.annotation.tailrec
class CSVReader2(source: Source) {
val QuoteChar = '"'
val LF = '\n'
val CR = '\r'
val Separator = ','
def readAll(lines:List[List[String]] = Nil):List[List[String]] = {
if (source.hasNext) {
return readAll(readLine()::lines)
}
return lines.reverse;
}
@tailrec final def readUntilQuote(buffered: AnyRef with BufferedIterator[Char], partial:String = ""):String = {
val char = buffered.next()
val next = if(buffered.hasNext) buffered.head else ""
(char, next) match {
case (QuoteChar, QuoteChar) => readUntilQuote(buffered, partial + buffered.next()) //We've read both charachters so skip
case (QuoteChar, _) => partial
case _ => readUntilQuote(buffered, partial + char)
}
}
def readLine():List[String] = {
val buffered = source.buffered
@tailrec def readLine(tokens:List[String] , partialToken:String):List[String] = {
val finished = {() => (partialToken::tokens).reverse}
if (!buffered.hasNext) return finished()
val char=buffered.next()
val subsequentChar = if (buffered.hasNext) buffered.head
(char, subsequentChar) match {
case (QuoteChar, x) if x != QuoteChar =>
readLine(tokens, partialToken + readUntilQuote(buffered))
case (QuoteChar, QuoteChar) =>
buffered.next();
readLine(tokens, partia
Is it well readable or should it be formulated differently? To me, there is a lot of lines in the main function which doesn't quite bode right.
It is functioning and I can provide my JUnit tests to prove it. Not all tests pass as those dealing with whitespace are now different.
I didn't want to use any parsing library or support as that doesn't help me learn the core of the language.
```
package com.wesleyacheson
import scala.io.Source
import scala.annotation.tailrec
class CSVReader2(source: Source) {
val QuoteChar = '"'
val LF = '\n'
val CR = '\r'
val Separator = ','
def readAll(lines:List[List[String]] = Nil):List[List[String]] = {
if (source.hasNext) {
return readAll(readLine()::lines)
}
return lines.reverse;
}
@tailrec final def readUntilQuote(buffered: AnyRef with BufferedIterator[Char], partial:String = ""):String = {
val char = buffered.next()
val next = if(buffered.hasNext) buffered.head else ""
(char, next) match {
case (QuoteChar, QuoteChar) => readUntilQuote(buffered, partial + buffered.next()) //We've read both charachters so skip
case (QuoteChar, _) => partial
case _ => readUntilQuote(buffered, partial + char)
}
}
def readLine():List[String] = {
val buffered = source.buffered
@tailrec def readLine(tokens:List[String] , partialToken:String):List[String] = {
val finished = {() => (partialToken::tokens).reverse}
if (!buffered.hasNext) return finished()
val char=buffered.next()
val subsequentChar = if (buffered.hasNext) buffered.head
(char, subsequentChar) match {
case (QuoteChar, x) if x != QuoteChar =>
readLine(tokens, partialToken + readUntilQuote(buffered))
case (QuoteChar, QuoteChar) =>
buffered.next();
readLine(tokens, partia
Solution
Here are a few things, going from smallest to the more significant.
- Try to avoid using return. It isn't idiomatic, and for good reason. So instead of writing
if (cond) return a; return byou should preferif (cond) a else b
- Unless I'm missing anything, in
readUntilQuote's signaturebufferedshould be of typeBufferedIterator[Char]instead ofAnyRef with BufferedIterator[Char]. TheAnyRefthere doesn't do anything useful.
- You can use
Sourceand still have functional code. Specifically, try looking atSource.getLines(). It returns anIterator[String]that is lazily-evaluated but can still be used functionally almost like other collections (you canmap,fold,filter, etc.)
Context
StackExchange Code Review Q#27206, answer score: 2
Revisions (0)
No revisions yet.