Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 从字符串中提取数字。正则表达式与Try构造?_Regex_Performance_Scala_Exception Handling - Fatal编程技术网

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

Regex 从字符串中提取数字。正则表达式与Try构造?,regex,performance,scala,exception-handling,Regex,Performance,Scala,Exception Handling,这个问题的灵感来自于这个问题 假设我们有一个任意字母和数字字符串的列表: val ls = List("The", "first", "one", "is", "11", "the", "second", "is" "22") 目标是形成从原始列表中提取的数字列表:val nums:list[Int]=list(11,22) 可能有两种不同的方法(AFAIK): 使用尝试构造: val nums = ls.flatMap(s => Try(s.toInt).toOption) 这个解

这个问题的灵感来自于这个问题

假设我们有一个任意字母和数字字符串的
列表

val ls = List("The", "first", "one", "is", "11", "the", "second", "is" "22") 
目标是形成从原始列表中提取的数字列表:
val nums:list[Int]=list(11,22)

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

  • 使用
    尝试
    构造:

    val nums = ls.flatMap(s => Try(s.toInt).toOption)
    
    这个解决方案看起来很简洁,但处理异常会有巨大的开销

  • 使用
    匹配
    方法:

    val nums = ls.filter(_.matches("\\d+")).map(_.toInt)
    
    这里最耗时的部分是regexp匹配

  • 哪一个性能更好


    从我的观点来看,在这样简单的操作中使用异常机制就像“用大锤敲开螺母”。

    我强烈建议您自己测试一下,您可以学到很多!开始Scala REPL:

    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()
    
    我们已经了解到在平面图中处理异常是一种非常低效的方法。这部分是因为异常处理会产生错误的汇编代码,部分是因为带有选项的flatMaps会进行大量额外的分配和装箱。正则表达式快约8倍!但是…正则表达式快吗

    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
    
    scala>def3(l:List[String],n:Int)={
    变量i=0
    而(iprintTime(f3(列表,100000))//isDigit
    时间:时间:70.960ms
    

    用character
    isDigit
    调用替换regex给了我们另一个数量级的改进。这里的教训是不惜一切代价避免try/catch处理,尽可能避免使用regex,并且不要害怕编写性能比较

    不要在正常控制流中使用异常。它具有误导性,不利于性能,并且无法扩展。对异常情况使用异常。我不是说你应该使用正则表达式,但是你可以通过a)(重新)使用预编译的正则表达式来优化你的版本,例如
    val Reg=“(\\d+).r
    和b)在一个步骤而不是两个步骤中进行
    过滤和
    映射,例如
    ls。收集{case Reg(n)=>n.toInt}
    如果它真的是关于性能(而不是关于风格或习惯用法):在您的示例中,9个元素中只有2个是有效数字。这是你输入列表的典型组成部分吗?如果不了解这一方面,讨论绩效就没有意义。如果列表中几乎不包含非数字的字符串,那么异常变量肯定会更快(因为没有什么可捕获的),而正则表达式变量的性能会更好,因为列表中的无效数字越多。你的问题没有通用的答案。@fxlae我正在学习scala,当我看到我在文章开头提到的问题最流行的答案是使用
    Try
    时,这个问题出现了,我认为这不太好。对我的问题IMHO的普遍回答应该考虑三种不同的情况:如果F是满足列表中的数目的可能性比第一种情况f是几乎0,则第二f= 0,5,最后f几乎为1。顺便说一句:我对堆栈溢出非常陌生,我应该用这些细节更新我的问题还是注释就足够了?拿一个只包含代表有效数字的字符串的列表来说,异常变量会快得多。是的,您使用了OP发布的列表,但我不确定OP一开始是否意识到这个问题。我想说的是:基准测试是一个困难的话题,特别是当我们不能对输入做出合理的假设时。你是对的,如果从不抛出异常,那么
    Try
    版本几乎与
    isDigit
    版本一样快:在一个包含8个数字字符串的列表上测试1m次迭代,时间是1.428秒(Try),4.631s(regex)和0.938s(isDigit)。添加一个非数字元素,时间为:7.148s(Try)、5.962s(regex)和0.992s(isDigit)。如果您以合理的频率抛出异常(这里大约有10%的元素),那么Try肯定是最慢的模型。
    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
    
    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