score:0

Here is a simple 1-pass solution. Let me know if it's fast enough.

I'm no expert in URLs, so it might need tuning. Basically it assumes that there are no unescaped spaces, '?', '&' or '=' characters.

It can be further smoothed with low-level opti.

def extractParams(params: List[String], from: String): Map[String, String] = {
  val a = from.toCharArray
  val len = a.length

  import scala.annotation.tailrec
  @tailrec
  def extract(p: Set[String], start: Int, results: Map[String, String]): Map[String, String] = {
    var paramStart = start
    var nextEquals = -1
    var nextAmpersand = -1

    if (start == 0) {  // find start of params
      var i = 0
      while (i < len && a(i) != '?') {
        i += 1
      }
      if (i == len) return results
      paramStart = i
    }

    { // find equals
      var i = paramStart
      while (i < len && a(i) != '=') {
        i += 1
      }
      if (i == len) return results
      nextEquals = i
    }

    { // find nextAmpersand or end
      var i = nextEquals
      while (i < len && !(a(i) == '&' || a(i) == ' ')) {
        i += 1
      }
      nextAmpersand = i
    }
    val paramNameArr = new Array[Char](nextEquals - paramStart - 1)
    System.arraycopy(a, paramStart + 1, paramNameArr, 0, nextEquals - paramStart - 1)
    val paramName = new String(paramNameArr)
    var newResults = results
    var newP = p
    if (p.contains(paramName)) { // find param value
      val paramValueArr = new Array[Char](nextAmpersand - nextEquals - 1)
      System.arraycopy(a, nextEquals + 1, paramValueArr, 0, nextAmpersand - nextEquals - 1)
      val paramValue = new String(paramValueArr)
      newResults = newResults + (paramName -> paramValue)
      newP = p - (paramName)
    }
    if (nextAmpersand == len || a(nextAmpersand) == ' ') { // check for end
      return newResults
    } else {
      return extract(newP, nextAmpersand, newResults)
    }
  }
  extract(params.toSet, "GET ".length, Map.empty)
}

Related Query