Scala 将文件转换为CSV

Scala 将文件转换为CSV,scala,csv,Scala,Csv,我有一个平面文本文件,格式如下 98430John Smith Y 98431Mary Jones N 98432Michael Johnson Y 前5个字符是ID 接下来的12个字符是名字 接下来的12个字符是姓氏 最后1个字符是Y/N值 我一直在使用Java打开该文件,并使用子字符串和FileInputStream拆分该文件 FileInputStream fis = new FileInputStream(fin)

我有一个平面文本文件,格式如下

98430John        Smith       Y
98431Mary        Jones       N
98432Michael     Johnson     Y
  • 前5个字符是ID
  • 接下来的12个字符是名字
  • 接下来的12个字符是姓氏
  • 最后1个字符是Y/N值
我一直在使用Java打开该文件,并使用子字符串和FileInputStream拆分该文件

FileInputStream fis = new FileInputStream(fin);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));

String line = null;
while ((line = br.readLine()) != null) {
   String csvString = str.substring(5)+","str.substring(6, 18);
}

br.close();
我现在想做同样的事情,但是在Scala。我知道我可以通过导入Java库来实现这一点,但我只是想知道,有没有一种更优雅、更纯粹的Scala方法来实现这一点?

您可以用来读取文件

示例代码(无异常处理!):


处理I/O可能永远不会优雅,因为您总是要考虑I/O异常的发生。一旦你必须处理异常,你就不再有好的函数(在数学意义上,即没有状态和确定性结果)。有一种情况可以优雅地处理异常行为:如果异常是结果的一部分(例如,如果您正在编写测试引擎),则可以将结果指定为类型
Try[Something]
所以java.io或java.nio是不错的选择

考虑到可测试性,将i/o访问与转换分开。首先读取整个输入文件(如果它至少适合内存),然后将其转换为csv字符串

您的输入格式可以很容易地表示为正则表达式,您可以根据正则表达式匹配输入行。假设ID总是一个整数,regexp可以如下所示:
(\d{5})(.{12})(.{12})([Y,N])

给定输入行上的迭代器,可以使用fold和regexp匹配器将输入转换为csv字符串:

object ToCSV {

  val InputFormat = "(\\d{5})(.{12})(.{12})([Y,N])".r

  def main(args: Array[String]): Unit = {
    // Assume the input to be read from file using a BufferedReader
    val input =
      """98430John        Smith       Y
        |98431Mary        Jones       N
        |98432Michael     Johnson     Y""".stripMargin
    val inputLines = input.lines 

    val csvString =
      (inputLines foldLeft "") {
        case (accumulator, InputFormat(id, firstName, lastName, yesOrNo)) =>
          s"$accumulator$id,${firstName.trim},${lastName.trim},$yesOrNo\n"
      }

    print(csvString)
  }
}
与正则表达式匹配的好处在于字符串看起来像一个元组。在代码中,
“#######firstName lastName X”
与具有
案例类InputFormat(id、firstName、lastName、yesOrNo)的实例是无法区分的

Edit:实际上,如果将正则表达式更改为
(\d{5})(\S{1,12})\S*(\S{1,12})\S*([Y,N])
,则可以取消对
.trim
的调用,但是名字和姓氏不能包含空格

正是这样的问题(解决方案——Java或Scala——基本上糟透了)让我觉得Fortran格式描述符()并不完全是个坏主意。。。
object ToCSV {

  val InputFormat = "(\\d{5})(.{12})(.{12})([Y,N])".r

  def main(args: Array[String]): Unit = {
    // Assume the input to be read from file using a BufferedReader
    val input =
      """98430John        Smith       Y
        |98431Mary        Jones       N
        |98432Michael     Johnson     Y""".stripMargin
    val inputLines = input.lines 

    val csvString =
      (inputLines foldLeft "") {
        case (accumulator, InputFormat(id, firstName, lastName, yesOrNo)) =>
          s"$accumulator$id,${firstName.trim},${lastName.trim},$yesOrNo\n"
      }

    print(csvString)
  }
}