从字符串中提取数字。正则表达式与Try构造?

时间:2016-11-08 11:08:22

标签: regex performance scala exception-handling

这个问题的灵感来自Extract numbers from String Array问题。

考虑我们有List任意字母和数字字符串:

val ls = List("The", "first", "one", "is", "11", "the", "second", "is" "22") 

目标是形成从原始列表中提取的数字列表:val nums: List[Int] = List(11, 22)

有两种不同的方法(AFAIK):

  1. 使用Try构造:

    val nums = ls.flatMap(s => Try(s.toInt).toOption)
    

    此解决方案看起来简洁,但处理异常会产生巨大的开销。

  2. 使用matches方法:

    val nums = ls.filter(_.matches("\\d+")).map(_.toInt)
    

    这里最耗时的部分是正则表达式匹配。

  3. 哪一项表现更好?

    从我的角度来看,在如此简单的操作中使用异常机制就像是“使用大锤来破解坚果”。

1 个答案:

答案 0 :(得分:2)

我强烈建议你自己测试这些东西,你可以学到很多东西!开始Scala REPL:

void test()
{ 
string connStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\\Database1.accdb;Persist Security Info=False;";
            OleDbConnection conn = new OleDbConnection(baglantiCumlesi);
            conn.Open();
            conn.Close();
}

好的,环境已经设置好了。这是你的第一个功能(尝试):

scala> import scala.util.Try
import scala.util.Try

< import printTime function from our repo >

scala> val list = List("The", "first", "one", "is", "11", "the", "second", "is", "22")
list: List[String] = List(The, first, one, is, 11, the, second, is, 22)

scala> var x: List[Int] = Nil
x: List[Int] = List()

第二个功能(正则表达式):

scala> def f1(l: List[String], n: Int) = { 
  var i = 0
  while (i < n) { 
    x = l.flatMap(s => Try(s.toInt).toOption)
    i += 1 
  }
}
f1: (l: List[String], n: Int)Unit

时序:

scala> def f2(l: List[String], n: Int) = { 
  var i = 0
  while (i < n) { 
    x = l.filter(_.matches("\\d+")).map(_.toInt)
    i += 1 
  }
}
f2: (l: List[String], n: Int)Unit

好吧,我们已经了解到在flatMap中处理异常是一种非常低效的方法。这部分是因为异常处理会产生错误的汇编代码,部分原因是带有选项的flatMaps会进行大量的额外分配和装箱。正则表达式快8倍!但是......快速正则表达式吗?

scala> printTime(f1(list, 100000)) // Try
time: 4.152s

scala> printTime(f2(list, 100000)) // regex
time: 565.107ms

用字符scala> def f3(l: List[String], n: Int) = { var i = 0 while (i < n) { x = l.filter(_.forall(_.isDigit)).map(_.toInt) i += 1 } } f3: (l: List[String], n: Int)Unit scala> printTime(f3(list, 100000)) // isDigit time: time: 70.960ms 调用替换正则表达式给了我们另一个数量级的改进。这里的教训是不惜一切代价避免尝试/捕获处理,尽可能避免使用正则表达式,并且不要害怕编写性能比较!