Skip to content

Instantly share code, notes, and snippets.

@azakordonets
Forked from penland365/PercentEncoder
Created July 7, 2017 13:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azakordonets/c7c6a8033810ae2ce102464e84e63567 to your computer and use it in GitHub Desktop.
Save azakordonets/c7c6a8033810ae2ce102464e84e63567 to your computer and use it in GitHub Desktop.
A Scala Object to do simple RFC3986 URL encoding.
package com.sabrelabs.twitter.auth
import scala.collection.BitSet
import scala.annotation.tailrec
import scala.runtime.RichInt
import scala.collection.mutable.ListBuffer
object PercentEncoder {
def encodeRFC3986(str: String): String = {
val strBytes = str.getBytes("UTF-8").toList
val encodedBytes = new ListBuffer[Byte]
strBytes.foreach(byte => {
if(allowedBytes.contains(byte)){
encodedBytes += byte
} else {
encodedBytes += PercentByte
new RichInt(byte.toInt).toHexString.takeRight(2).foreach({
char => encodedBytes += char.toUpper.toByte
})
}
})
stringFromByteList("", encodedBytes.toList)
}
private[this] val PercentByte = "%".charAt(0).toByte
private[this] val allowedAsciiChars = strListToCharList(Nil, List(
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
"T", "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z",
"-", ".", "_", "~"
))
private[this] val allowedBytes = buildAllowedAsciiByteSet(BitSet.empty, byteListFromCharList(Nil, allowedAsciiChars))
@tailrec
private[this] def byteListFromCharList(bytes: List[Byte], chars: List[Char]): List[Byte] = {
if(chars.isEmpty) return bytes
byteListFromCharList(bytes.::(chars.head.toByte), chars.tail)
}
@tailrec
private[this] def buildAllowedAsciiByteSet(set: BitSet, bytes: List[Byte]): BitSet = {
if(bytes.isEmpty) return set
buildAllowedAsciiByteSet(set + bytes.head, bytes.tail)
}
@tailrec
private[this] def strListToCharList (chars: List[Char], strings: List[String]): List[Char] = {
if(strings.isEmpty) return chars
strListToCharList(chars ::: strings.head.toCharArray.toList, strings.tail)
}
@tailrec
private[this] def stringFromByteList(str: String, bytes: List[Byte]): String = {
if(bytes.isEmpty) return str
stringFromByteList(str + bytes.head.toChar, bytes.tail)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment