Home > Mobile >  Splitting text files and returning only the end in scala
Splitting text files and returning only the end in scala

Time:02-08

I want to read a text file from scala named "c.txt" that contains

CatManC_NAA
Foranz_CSW
Foresan_SQW

and return only the second part of the txt file as a string. Ex: NAA, CSW when entering "CatManC" or "Foranz" as a parameter while ignoring capitalization. This is my code at the moment.

object Test {
  def getCode(fileName: String, nameInput:String): String={
  code:String=""
  for (line <- Source.fromFile(filename).getLines) {
    line.split("_")
   if (nameInput==line){
    line.takeRight(3)
     code =line
}
   else{
   return ""
}
    
   
  }
code
}

I'm an amateur at coding and also new to the language. Any help will be appreciated.

CodePudding user response:

I suggest to write something like this:

  def getCode(fileName: String, nameInput: String): String = {
    import scala.util.control.Breaks
    var code = ""
    val source = Source.fromFile(fileName)
    val loopBreak = new Breaks
    loopBreak.breakable {
      for (line <- source.getLines()) {
        if (line.toLowerCase.contains(nameInput.toLowerCase)) {
          code = line.split("_")(1)
          loopBreak.break()
        }
      }
    }
    source.close()
    code
  }

Here Breaks needs to stop read file when we find what we are looking for. Method toLowerCase need to ignore capitalisation on both sides in file and in input.

CodePudding user response:

This would be the idiomatic, safe and efficient way of doing what you want.

import scala.io.Source
import scala.util.{Try, Using}

def getCode(fileName: String, nameInput: String): Try[Option[String]] = {
  val key = nameInput.toLowerCase

  Using(Source.fromFile(fileName)) { source =>
    source.getLines().map(_.split('_').map(_.toLowerCase).toList).collectFirst {
      case `key` :: value :: Nil => value
    }
  }
}

The Try is used to signal that processing the file may fail for multiple reasons; e.g. the file not existing.
The Option is used to signal that the nameInput key may not be present, thus there may not be output.

Ideally, you would handle both kinds of errors, probably by turning everything into an Either[Error, String] so you don't have to deal with nesting; like this:

import scala.io.Source
import scala.util.{Failure, Success, Try, Using}

sealed abstract class GetCodeError(cause: Option[Throwable]) extends Throwable(cause.orNull)
object GetCodeError {
  final case class FileError(cause) extend GetCodeError(cause = Some(cause))
  final case object KeyNotFoundError extends GetCodeError(cause = None)
}

def getCode(fileName: String, nameInput: String): Either[GetCodeError, String] = {
  val key = nameInput.toLowerCase

  val result = Using(Source.fromFile(fileName)) { source =>
    source.getLines().map(_.split('_').map(_.toLowerCase).toList).collectFirst {
      case `key` :: value :: Nil => value
    }
  }

  result match {
    case Sucess(opt) =>
      opt.toRight(left = GetCodeError.KeyNotFoundError)

    case Failure(ex) =>
      Left(GetCodeError.FileError(cause = ex))
  }
}

Or you may just forget about those errors and let the program crash if something wrong happens; like this:

import scala.io.Source
import scala.util.Using

def getCode(fileName: String, nameInput: String): String = {
  val key = nameInput.toLowerCase

  Using.resource(Source.fromFile(fileName)) { source =>
    source.getLines().map(_.split('_').map(_.toLowerCase).toList).collectFirst {
      case `key` :: value :: Nil => value
    }.get
  }
}

But please, don't do that on a real project. Although, this may be fine for a quick script.


If you have any questions about the code, please feel free to ask them!

  •  Tags:  
  • Related