Skip to content

Adding splitAsList to String #113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions src/main/scala/scala/next/NextStringOpsExtensions.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package scala
package next

private[next] final class NextStringOpsExtensions(
private val str: String
) extends AnyVal {
/** Split this string around the separator character; as a [[List]]
*
* If this string is blank,
* returns an empty list.
*
* If this string is not a blank string,
* returns a list containing the substrings terminated by the start of the string,
* the end of the string or the separator character.
*
* By default, this method discards empty substrings.
*
* @param separator the character used as the delimiter.
* @param preserveEmptySubStrings set as `true` to preserve empty substrings.
* @return a [[List]] of substrings.
*/
def splitAsList(separator: Char, preserveEmptySubStrings: Boolean = false): List[String] = {
@annotation.tailrec
def loop(currentIdx: Int, acc: List[String]): List[String] = {
def addToAcc(substring: String): List[String] =
if (substring.isEmpty && !preserveEmptySubStrings)
acc
else
substring :: acc

val newIndex = str.lastIndexOf(separator, currentIdx - 1)
if (newIndex == -1)
addToAcc(substring = str.substring(0, currentIdx))
else
loop(
currentIdx = newIndex,
acc = addToAcc(substring = str.substring(newIndex + 1, currentIdx))
)
}

loop(
currentIdx = str.length,
acc = List.empty
)
}
}
7 changes: 7 additions & 0 deletions src/main/scala/scala/next/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

package scala

import scala.language.implicitConversions

package object next {
implicit final class OptionOpsExtensions[A](private val v: Option[A]) extends AnyVal {
/** Apply the side-effecting function `f` to the option's value
Expand All @@ -22,4 +24,9 @@ package object next {
*/
def tapEach[B](f: A => B): Option[A] = { v.foreach(f); v }
}

implicit final def scalaNextSyntaxForStringOps(
str: String
): NextStringOpsExtensions =
new NextStringOpsExtensions(str)
}
107 changes: 107 additions & 0 deletions src/test/scala/scala/next/TestStringOpsExtensions.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/

package scala.next

import org.junit.Assert._
import org.junit.Test

final class TestStringOpsExtensions {
@Test
def splitAsListEmptyStringNoPreserveEmpty(): Unit = {
val str = ""

assertTrue(str.splitAsList(',').isEmpty)
}

@Test
def splitAsListEmptyStringPreserveEmpty(): Unit = {
val str = ""
val expected = List("")

assertEquals(expected, str.splitAsList(separator = ',', preserveEmptySubStrings = true))
}

@Test
def splitAsListBlankStrings(): Unit = {
val strings = List(
" ",
" ",
"\t",
"\t\t\t",
"\n",
"\n\n\n",
" \t \t \n"
)

strings.foreach { str =>
val expected = List(str)
assertEquals(expected, str.splitAsList(','))
}
}

@Test
def splitAsListDelimiterNotFound(): Unit = {
val str = "Hello World"
val expected = List(str)

assertEquals(expected, str.splitAsList(','))
}

@Test
def splitAsListSingleDelimiter(): Unit = {
val str = "Hello,World"
val expected = List("Hello", "World")

assertEquals(expected, str.splitAsList(','))
}

@Test
def splitAsListMultipleDelimiters(): Unit = {
val str = "Hello,World,Good,Bye,World"
val expected = List("Hello", "World", "Good", "Bye", "World")

assertEquals(expected, str.splitAsList(','))
}

@Test
def splitAsListEmptySubStrings(): Unit = {
val str = "Hello,,World,"
val expected = List("Hello", "World")

assertEquals(expected, str.splitAsList(','))
}

@Test
def splitAsListDelimiterAtTheEnd(): Unit = {
val str = "Hello,World,"
val expected = List("Hello", "World")

assertEquals(expected, str.splitAsList(','))
}

@Test
def splitAsListDelimiterAtTheBeginning(): Unit = {
val str = ",Hello,World"
val expected = List("Hello", "World")

assertEquals(expected, str.splitAsList(','))
}

@Test
def splitAsListPreserveEmptySubStrings(): Unit = {
val str = ",Hello,,World,"
val expected = List("", "Hello", "", "World", "")

assertEquals(expected, str.splitAsList(separator = ',', preserveEmptySubStrings = true))
}
}