有效地从同一个字符串中提取多个子字符串

时间:2014-11-14 15:33:39

标签: scala

我有一个包含键值对的URL字符串的大型数据集,我想从该字符串中捕获值列表。字符串的一个示例如下:

"GET /no_cache/bi_page?Log=1&pg_inst=600474500174606089&pg=mdot_fyc_pnt&platform=mdot&ver=10.c110&pid=157876860906745096&rid=157876731027276387&srch_id=-2&row=7&seq=1&tot=1&tsp=1&test_name=m_control&logDomain=http%3A%2F%2Fwww.xyz.com&ref_url=http%3A%2F%2Fm.xyz.com%2F&z=44134 HTTP/1.1"

所以如果我要返回的值列表来自键:“pg”,“test_name”,“some_other_key”......我希望函数返回(“mdot_fyc”,“m_control”,“NA”)这一行。

我可以写三个单独的正则表达式行来捕获每个值。但是其中一些字符串很长,我可以提取数十个这些值,而不是只提取三个。

从同一个字符串中提取多个值的最有效方法是什么?

1 个答案:

答案 0 :(得分:0)

这是一个简单的1遍解决方案。如果它足够快,请告诉我。

我没有网站专家,所以可能需要调整。基本上它假定没有未转义的空间,'?''&'或者' ='字符。

可以使用低级别的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)
}