G.Saleh
G.Saleh

Reputation: 509

String.split() with condition or regex

I want to convert a string to list with comma separator but with condition if i have a specific word after comma.

this is my input string:

val x = "StructField(AverageOverallRating1,DoubleType,true),StructType(AverageOverallRating2,DoubleType,true),ArrayType(AverageOverallRating3,DoubleType,true),StructType(StructField(AverageOverallRating1,DoubleType,true),StructField(AverageOverallRating1,DoubleType,true))"

I want to get a result like this :

StructField(AverageOverallRating1,DoubleType,true)
StructType(AverageOverallRating2,DoubleType,true)
ArrayType(AverageOverallRating3,DoubleType,true)
StructType(StructField(AverageOverallRating1,DoubleType,true),StructField(AverageOverallRating1,DoubleType,true))

I tried to split(",") but it doesn't work, I think the solution is with regex but I can't find the right expression

Upvotes: 0

Views: 125

Answers (1)

Mateusz Kubuszok
Mateusz Kubuszok

Reputation: 27535

If I were to parse that thing I would use type - and once I would get ADT with some reasonable representation I would decide how to handle it. For instance with fastparse 2 I would try to implement it somehow like this:

import fastparse._, NoWhitespace._

def boolean[_: P]: P[Boolean] = P( "true" | "false" ).map(_.toBoolean)

// assuming that there is a type DoubleType
sealed trait DoubleType
objecy DoubleType extends DoubleType
def doubleType[_ : P]: P[DoubleType] = P( "DoubleType" ).map(_ => DoubleType)

// assuming there is an enum AverageOverallRating with withName method
sealed trait AverageOverallRating
object AverageOverallRating {
  case object AverageOverallRating1 extends AverageOverallRating
  case object AverageOverallRating2 extends AverageOverallRating
  case object AverageOverallRating3 extends AverageOverallRating
  
  def withName(string: String): AverageOverallRating = ???
}
def averageOverallRating: P( "AverageOverallRating1" | "AverageOverallRating2" | "AverageOverallRating3" ).map(AverageOverallRating.withName)

sealed trait Entry

case class StructField(averageOverallRating: averageOverallRating, doubleType: DoubleType, boolean: Boolean) extends Entry
case class StructType(averageOverallRating: averageOverallRating, doubleType: DoubleType, boolean: Boolean) extends Entry
case class ArrayType(averageOverallRating: averageOverallRating, doubleType: DoubleType, boolean: Boolean) extends Entry

def structField[_ : P]: P[StructField] = P( "StructField" ~ "(" ~ averageOverallRating ~ "," ~ doubleType ~ "," ~ boolean ~ ")").map {
  case (_, _, a, _, b, _, c, _) => StructField(a, b, c)
}
def structType[_ : P]: P[StructType] = P( "StructType" ~ "(" ~ averageOverallRating ~ "," ~ doubleType ~ "," ~ boolean ~ ")").map {
  case (_, _, a, _, b, _, c, _) => StructField(a, b, c)
}
def arrayType[_ : P]: P[ArrayType] = P( "ArrayType" ~ "(" ~ averageOverallRating ~ "," ~ doubleType ~ "," ~ boolean ~ ")").map {
  case (_, _, a, _, b, _, c, _) => StructField(a, b, c)
}

def entry[_ : P]: P[Entry] = P(structField | structType | arrayType)

def entries[_ : P]: P[List[Entry]] = P( entry ~ ("," ~ entry).rep ).map { case (head, tail) =>
  head +: tail.toList.map(_._2)
}

val input = "StructField(AverageOverallRating1,DoubleType,true),StructType(AverageOverallRating2,DoubleType,true),ArrayType(AverageOverallRating3,DoubleType,true),StructType(StructField(AverageOverallRating1,DoubleType,true),StructField(AverageOverallRating1,DoubleType,true))"
val result = parse(input, entries(_))

(Disclaimer: this is just a quickly written draft/example/pseudocode, I don't expect it to compile and work immediately).

Once I would get result and made sure it is correct, I would just use the List[Entry] to produce the final result much, much easier, e.g.

entries.map(_.toString).mkString("\n")

Upvotes: 1

Related Questions