diff --git a/README.md b/README.md
index e95eb63..a1175c7 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,7 @@ UrlEncoder.endode("foo bar", spaceToPlus = true) // -> foo+bar
UrlEncoder.decode("a%20test%20%26") // -> a test &
UrlEncoder.decode("%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81") // -> %#okékÉȢ smile!😁
+UrlEncoder.decode("foo+bar", plusToSpace = true) // -> foo bar
```
## Gradle, Maven, etc.
@@ -54,7 +55,7 @@ repositories {
}
dependencies {
- implementation("net.thauvin.erik:urlencoder:1.0.1")
+ implementation("net.thauvin.erik:urlencoder:1.3.0")
}
```
diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts
index 19d997f..3ee47fe 100644
--- a/lib/build.gradle.kts
+++ b/lib/build.gradle.kts
@@ -23,7 +23,7 @@ plugins {
description = "A simple defensive library to encode/decode URL components"
group = "net.thauvin.erik"
-version = "1.2.1-SNAPSHOT"
+version = "1.3.0-SNAPSHOT"
val mavenName = "UrlEncoder"
diff --git a/lib/detekt-baseline.xml b/lib/detekt-baseline.xml
index 571f54a..2876ea2 100644
--- a/lib/detekt-baseline.xml
+++ b/lib/detekt-baseline.xml
@@ -10,5 +10,6 @@
MagicNumber:UrlEncoder.kt$UrlEncoder$4
MaxLineLength:UrlEncoder.kt$UrlEncoder$*
NestedBlockDepth:UrlEncoder.kt$UrlEncoder$@JvmStatic @JvmOverloads fun encode(source: String, allow: String = "", spaceToPlus: Boolean = false): String
+ NestedBlockDepth:UrlEncoder.kt$UrlEncoder$@JvmStatic fun decode(source: String, plusToSpace: Boolean = false): String
diff --git a/lib/pom.xml b/lib/pom.xml
index 7a70ae1..715598f 100644
--- a/lib/pom.xml
+++ b/lib/pom.xml
@@ -8,7 +8,7 @@
4.0.0
net.thauvin.erik
urlencoder
- 1.2.1-SNAPSHOT
+ 1.3.0-SNAPSHOT
UrlEncoder for Kotlin
A simple defensive library to encode/decode URL components
https://github.com/ethauvin/urlencoder
diff --git a/lib/src/main/kotlin/net/thauvin/erik/urlencoder/UrlEncoder.kt b/lib/src/main/kotlin/net/thauvin/erik/urlencoder/UrlEncoder.kt
index d0cc2c7..9347936 100644
--- a/lib/src/main/kotlin/net/thauvin/erik/urlencoder/UrlEncoder.kt
+++ b/lib/src/main/kotlin/net/thauvin/erik/urlencoder/UrlEncoder.kt
@@ -84,23 +84,24 @@ object UrlEncoder {
* encoding.
*/
@JvmStatic
- fun decode(source: String): String {
+ fun decode(source: String, plusToSpace: Boolean = false): String {
if (source.isEmpty()) {
return source
}
val length = source.length
- var out: StringBuilder? = null
+ val out: StringBuilder by lazy { StringBuilder(length) }
var ch: Char
var bytesBuffer: ByteArray? = null
var bytesPos = 0
var i = 0
+ var start = false
while (i < length) {
ch = source[i]
if (ch == '%') {
- if (out == null) {
- out = StringBuilder(length)
+ if (!start) {
out.append(source, 0, i)
+ start = true
}
if (bytesBuffer == null) {
// the remaining characters divided by the length of the encoding format %xx, is the maximum number
@@ -119,20 +120,30 @@ object UrlEncoder {
}
} else {
if (bytesBuffer != null) {
- out!!.append(String(bytesBuffer, 0, bytesPos, StandardCharsets.UTF_8))
+ out.append(String(bytesBuffer, 0, bytesPos, StandardCharsets.UTF_8))
+ start = true
bytesBuffer = null
bytesPos = 0
}
- out?.append(ch)
+ if (plusToSpace && ch == '+') {
+ if (!start) {
+ out.append(source, 0, i)
+ }
+ out.append(" ")
+ start = true
+ } else if (start) {
+ out.append(ch)
+ start = true
+ }
i++
}
}
if (bytesBuffer != null) {
- out!!.append(String(bytesBuffer, 0, bytesPos, StandardCharsets.UTF_8))
+ out.append(String(bytesBuffer, 0, bytesPos, StandardCharsets.UTF_8))
}
- return out?.toString() ?: source
+ return if (!start) source else out.toString()
}
/**
diff --git a/lib/src/test/kotlin/net/thauvin/erik/urlencoder/UrlEncoderTest.kt b/lib/src/test/kotlin/net/thauvin/erik/urlencoder/UrlEncoderTest.kt
index 4897040..24f1228 100644
--- a/lib/src/test/kotlin/net/thauvin/erik/urlencoder/UrlEncoderTest.kt
+++ b/lib/src/test/kotlin/net/thauvin/erik/urlencoder/UrlEncoderTest.kt
@@ -73,6 +73,14 @@ class UrlEncoderTest {
assertEquals(" ", decode(" "), "decode(' ')")
}
+ @Test
+ fun `Decode with Plus to Space`() {
+ assertEquals("foo bar", decode("foo+bar", true))
+ assertEquals("foo bar foo", decode("foo+bar++foo", true))
+ assertEquals("foo bar foo", decode("foo+%20bar%20+foo", true))
+ assertEquals("foo + bar", decode("foo+%2B+bar", plusToSpace = true))
+ }
+
@ParameterizedTest(name = "encode({0}) should be {1}")
@MethodSource("validMap")
fun `Encode URL`(source: String, expected: String) {