在正则表达式匹配公式中保留尾随零

时间:2016-03-11 21:47:29

标签: regex excel vba excel-vba

我已经编写了一个函数来处理有效数字减少百分比的计算,并且我在保留尾随零时遇到问题。 功能:

Function RegexReduction(IValue As Double, EValue As Double) As String
    Dim TempPercent As Double
    Dim TempString As String
    Dim NumFormat As String
    Dim DecPlaces As Long
    Dim regex As Object
    Dim rxMatches As Object

    TempPercent = (1 - EValue / IValue)
    NumFormat = "0"
    Set regex = CreateObject("VBScript.RegExp")
    With regex
        .Pattern = "([^1-8])*[0-8]{1}[0-9]?"
        .Global = False
    End With
    Set rxMatches = regex.Execute(CStr(TempPercent))
    If rxMatches.Count <> 0 Then
        TempString = rxMatches.Item(0)
        DecPlaces = Len(Split(TempString, ".")(1)) - 2
        If DecPlaces > 0 Then NumFormat = NumFormat & "." & String(DecPlaces, "0")
    End If
    RegexReduction = Format(TempPercent, NumFormat & "%")
End Function

在任何前导零或九之后将百分比修剪为两位数:

99.999954165%  ->  99.99954%
34.564968%     ->  35%
0.000516%      ->  0.00052%

我发现的一个问题与正则表达式无关,而是与Excel的四舍五入有关:

99.50%          ->  99.5%

是否有解决方案可以保存可在此处实现的尾随零?

2 个答案:

答案 0 :(得分:1)

这是一个UDF,它试图“读取”传入的原始(非百分比)值,以确定要包含的小数位数。

Function udf_Specific_Scope(rng As Range)
    Dim i As Long, str As String

    str = rng.Value2    'raw value is 0.999506 for 99.9506%

    For i = 1 To Len(str) - 1
        If Asc(Mid(str, i, 1)) <> 48 And _
           Asc(Mid(str, i, 1)) <> 57 And _
           Asc(Mid(str, i, 1)) <> 46 Then _
            Exit For
    Next i

    If InStr(1, str, Chr(46)) < i - 1 Then
        udf_Specific_Scope = Val(Format(rng.Value2 * 100, "0." & String(i - 3, Chr(48)))) & Chr(37)
    Else
        udf_Specific_Scope = Format(rng.Value2, "0%")
    End If

End Function

specific_scope

这里的缺点是从单元格条目中删除数值但是镜像了原始的RegEx方法。理想情况下,像上面这样的东西可以写成基于Application.Selection属性的子。只需突出显示(也就是选择)一些单元格,运行sub,它会为选择中的每个单元格分配一个正确的小数位数字格式。

答案 1 :(得分:1)

我建议使用LTrimReplace结合而不是(代价高昂的)正则表达式来计算DecPlaces的值的函数版本。 DecPlaces的计算已成为&#34;单行&#34;。

其他代码是相同的,除了额外调用CDec以避免CStr在值很小时返回科学记数法(如1.123642E-12)。

Function Reduction(IValue As Double, EValue As Double) As String
    Dim TempPercent As Double
    Dim TempString As String
    Dim NumFormat As String
    Dim DecPlaces As Long

    TempPercent = (1 - EValue / IValue)
     ' Apply CDec so tiny numbers do not get scientific notation
    TempString = CStr(CDec(TempPercent))
    ' Count number of significant digits present by trimming away all other chars,
    ' and subtract from total length to get number of decimals to display
    DecPlaces = Len(TempString) - 2 - _
        Len(LTrim(Replace(Replace(Replace(TempString, "0"," "), "9"," "), "."," ")))
    ' Prepare format of decimals, if any
    If DecPlaces > 0 Then NumFormat = "." & String(DecPlaces, "0")
    ' Apply format
    Reduction = Format(TempPercent, "0" & NumFormat & "%")
End Function

假设TempPercent的计算结果为0到1之间的值。

对您的代码的评论

您写道:

  

我发现的一个问题与正则表达式无关,而是与Excel的四舍五入有关:

99.50%          ->  99.5%

这实际上与Excel的舍入无关。在您的代码中以下

DecPlaces = Len(Split(TempString, ".")(1)) - 2

将评估为Len(Split("0.995", ".")(1)) - 21,因此您应用的格式为0.0%,说明您获得的输出。

还要意识到虽然正则表达式中有一个捕获组,但实际上并没有使用它。 rxMatches.Item(0)将为您提供完整匹配的字符串,而不仅仅是与捕获组的匹配。

对于正则表达式不产生匹配的情况,您应用0%的数字格式。任何除09之外没有其他数字的数字将不匹配。例如,0.099应显示格式0.000%以提供9.900,但使用的格式为0%,因为您没有Else块来处理此案例。< / p>

最后,CStr可以将数字转换为科学记数法,这也会产生错误的结果。似乎CDec可以避免这种情况。