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值
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)
}
}