Skip to content

Commit 1742d3d

Browse files
committed
Add splitAsList to String
1 parent 8359245 commit 1742d3d

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package scala
2+
package next
3+
4+
private[next] final class NextStringOpsExtensions(
5+
private val str: String
6+
) extends AnyVal {
7+
/** Split this string around the separator character; as a [[List]]
8+
*
9+
* If this string is blank,
10+
* returns an empty list.
11+
*
12+
* If this string is not a blank string,
13+
* returns a list containing the substrings terminated by the start of the string,
14+
* the end of the string or the separator character.
15+
*
16+
* By default, this method discards empty substrings.
17+
*
18+
* @param separator the character used as the delimiter.
19+
* @param preserveEmptySubStrings set as `true` to preserve empty substrings.
20+
* @return a [[List]] of substrings.
21+
*/
22+
def splitAsList(separator: Char, preserveEmptySubStrings: Boolean = false): List[String] = {
23+
@annotation.tailrec
24+
def loop(currentIdx: Int, acc: List[String]): List[String] = {
25+
def addToAcc(substring: String): List[String] =
26+
if (substring.isEmpty && !preserveEmptySubStrings)
27+
acc
28+
else
29+
substring :: acc
30+
31+
val newIndex = str.lastIndexOf(separator, currentIdx - 1)
32+
if (newIndex == -1)
33+
addToAcc(substring = str.substring(0, currentIdx))
34+
else
35+
loop(
36+
currentIdx = newIndex,
37+
acc = addToAcc(substring = str.substring(newIndex + 1, currentIdx))
38+
)
39+
}
40+
41+
loop(
42+
currentIdx = str.length,
43+
acc = List.empty
44+
)
45+
}
46+
}

src/main/scala/scala/next/package.scala

+7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
package scala
1414

15+
import scala.language.implicitConversions
16+
1517
package object next {
1618
implicit final class OptionOpsExtensions[A](private val v: Option[A]) extends AnyVal {
1719
/** Apply the side-effecting function `f` to the option's value
@@ -22,4 +24,9 @@ package object next {
2224
*/
2325
def tapEach[B](f: A => B): Option[A] = { v.foreach(f); v }
2426
}
27+
28+
implicit final def scalaNextSyntaxForStringOps(
29+
str: String
30+
): NextStringOpsExtensions =
31+
new NextStringOpsExtensions(str)
2532
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package scala.next
14+
15+
import org.junit.Assert._
16+
import org.junit.Test
17+
18+
final class TestStringOpsExtensions {
19+
@Test
20+
def splitAsListEmptyStringNoPreserveEmpty(): Unit = {
21+
val str = ""
22+
23+
assertTrue(str.splitAsList(',').isEmpty)
24+
}
25+
26+
@Test
27+
def splitAsListEmptyStringPreserveEmpty(): Unit = {
28+
val str = ""
29+
val expected = List("")
30+
31+
assertEquals(expected, str.splitAsList(separator = ',', preserveEmptySubStrings = true))
32+
}
33+
34+
@Test
35+
def splitAsListBlankStrings(): Unit = {
36+
val strings = List(
37+
" ",
38+
" ",
39+
"\t",
40+
"\t\t\t",
41+
"\n",
42+
"\n\n\n",
43+
" \t \t \n"
44+
)
45+
46+
strings.foreach { str =>
47+
val expected = List(str)
48+
assertEquals(expected, str.splitAsList(','))
49+
}
50+
}
51+
52+
@Test
53+
def splitAsListDelimiterNotFound(): Unit = {
54+
val str = "Hello World"
55+
val expected = List(str)
56+
57+
assertEquals(expected, str.splitAsList(','))
58+
}
59+
60+
@Test
61+
def splitAsListSingleDelimiter(): Unit = {
62+
val str = "Hello,World"
63+
val expected = List("Hello", "World")
64+
65+
assertEquals(expected, str.splitAsList(','))
66+
}
67+
68+
@Test
69+
def splitAsListMultipleDelimiters(): Unit = {
70+
val str = "Hello,World,Good,Bye,World"
71+
val expected = List("Hello", "World", "Good", "Bye", "World")
72+
73+
assertEquals(expected, str.splitAsList(','))
74+
}
75+
76+
@Test
77+
def splitAsListEmptySubStrings(): Unit = {
78+
val str = "Hello,,World,"
79+
val expected = List("Hello", "World")
80+
81+
assertEquals(expected, str.splitAsList(','))
82+
}
83+
84+
@Test
85+
def splitAsListDelimiterAtTheEnd(): Unit = {
86+
val str = "Hello,World,"
87+
val expected = List("Hello", "World")
88+
89+
assertEquals(expected, str.splitAsList(','))
90+
}
91+
92+
@Test
93+
def splitAsListDelimiterAtTheBeginning(): Unit = {
94+
val str = ",Hello,World"
95+
val expected = List("Hello", "World")
96+
97+
assertEquals(expected, str.splitAsList(','))
98+
}
99+
100+
@Test
101+
def splitAsListPreserveEmptySubStrings(): Unit = {
102+
val str = ",Hello,,World,"
103+
val expected = List("", "Hello", "", "World", "")
104+
105+
assertEquals(expected, str.splitAsList(separator = ',', preserveEmptySubStrings = true))
106+
}
107+
}

0 commit comments

Comments
 (0)