0

VB.net 中的正则表达式代码是否已知很慢?

我接管了一些清理大量文本数据的代码。代码运行得相当慢,所以我一直在寻找一些方法来加快它。我发现了一些运行很多的函数,我认为这可能是问题的一部分。

这是清除电话号码的原始代码:

        Dim strArray() As Char = strPhoneNum.ToCharArray
        Dim strNewPhone As String = ""
        Dim i As Integer

        For i = 0 To strArray.Length - 1
            If strArray.Length = 11 And strArray(0) = "1" And i = 0 Then
                Continue For
            End If

            If IsNumeric(strArray(i)) Then
                strNewPhone = strNewPhone & strArray(i)
            End If
        Next

        If Len(strNewPhone) = 7 Or Len(strNewPhone) = 10 Then
            Return strNewPhone
        End If

我重写了代码以使用正则表达式消除数组和循环。

        Dim strNewPhone As String = ""
        strNewPhone = Regex.Replace(strPhoneNum, "\D", "")
        If strNewPhone = "" OrElse strNewPhone.Substring(0, 1) <> "1" Then
            Return strNewPhone
        Else
            strNewPhone = Mid(strNewPhone, 2)
        End If

        If Len(strNewPhone) = 7 Or Len(strNewPhone) = 10 Then
            Return strNewPhone
        End If

运行几次测试后,新代码比旧代码慢得多。VB.net 中的正则表达式是否很慢,我是否添加了其他一些问题,或者原始代码是否正常?

4

3 回答 3

3

我使用 Visual Studio Profiler 进行了一些测试,但没有得到与您相同的结果。有一个逻辑错误是您的 Regex 函数,如果数字不是以1. 我在测试中纠正了这一点。

  1. 我在测试中意识到,无论哪个函数先执行,最后执行都会受到惩罚。所以我独立地执行了每个函数,并且之前运行了一个启动函数。
  2. 根据测试,我使用电话号码(如不同长度的模式)执行了 10000 或 100000 次函数。每种方法都得到相同的数字。

结果

一般来说,我的方法总是稍微快一些。

  1. 我做了一个便宜的计时器测试,原始功能慢了一倍。
  2. Profiler 显示原始方法使用的内存比我们的方法多 60%。
  3. Profiler 显示原始方法的工作时间是原来的八倍。
  4. Profiler 显示原始方法多花费了大约 40% 的处理器周期。

我的结论

在所有测试中,原始方法要慢得多。如果它在一项测试中表现得更好,那么我就能解释我们的差异。如果你完全孤立地测试了这些方法,我想你会想出类似的东西。

我最好的猜测是其他东西正在影响您的结果,并且您对原始方法更好的评估是错误的。

您修改后的功能

Function GetPhoneNumberRegex(strPhoneNum As String)
    Dim strNewPhone As String = ""
    strNewPhone = Regex.Replace(strPhoneNum, "\D", "")
    If strNewPhone <> "" And strNewPhone.Substring(0, 1) = "1" Then
        strNewPhone = Mid(strNewPhone, 2)
    End If

    If Len(strNewPhone) = 7 Or Len(strNewPhone) = 10 Then
        Return strNewPhone
    End If

    Return ""
End Function

我的功能

Function GetPhoneNumberMine(strPhoneNum As String)
    Dim strNewPhone As String = Regex.Replace(strPhoneNum, "\D", "")
    If (strNewPhone.Length >= 7 And strNewPhone(0) = "1") Then
        strNewPhone = strNewPhone.Remove(0, 1)
    End If

    Return If(strNewPhone.Length = 7 OrElse strNewPhone.Length = 10, strNewPhone, "")
End Function
于 2013-08-19T19:02:45.520 回答
1

如果遇到这种情况,重复这样的事情会减慢你的速度。

 If Len(strNewPhone) = 7 Or Len(strNewPhone) = 10 Then
     Return strNewPhone
 End If

相反,这样做...

     Dim value = Len(strNewPhone)
     If value = 7 OrElse value = 10 Then
         Return strNewPhone
     End If

但是您仍然应该测量各个部分(条件/陈述)以确定其中哪些会减慢您的速度,但前提是它确实很重要。

于 2013-08-19T17:32:02.273 回答
1

我不知道您是否看到了真正的问题,但是您显示的代码可能会很慢,因为每次使用正则表达式时都会重新编译它。

看看这是否更好:

Regex rx = new Regex("\D") ' do this once, use it each time

参考MSDN

于 2013-08-19T17:32:34.413 回答