如何将以分数形式书写的一般数据转换为 3 位小数。替换“0”。和 ”。”

How to turn general data written as fractions into 3 place decimal numbers. Replace " 0." with "."

我正在尝试将以 3/4" 或 13 7/32" 等分数表示的一般数据转换为 3 位小数,例如 0.750 或 13.219。

我有一个有效的 table 替代品,可以处理 0 到 1" 的分数。它不能处理像 13 7/32" 这样的带分数。它留给我 13 0.219,这就是我需要替换“0”的原因。和 ”。”将 13 和 219 连在一起并加上一个小数点。

我们分多个步骤进行此数据转换并手动输入,因为 Excel 尝试将一些分数(如 3/4")转换为日期。

原始数据

结果数据

Sub FractionConvertMTO()
'this section works
For i = 6 To 70
    Worksheets("BOM").Range("F6:H48").Select
    Selection.Replace what:=Cells(i, 21).Value, Replacement:=Cells(i, 22).Value, _
      LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False
Next

 'this section doesn't work
For i = 6 To 70
    Worksheets("BOM").Range("F6:H48").Select
    str1 = " "
    str1 = Trim(Replace(str1, " ", "+"))
Next

'this section changes the format.
For i = 66 To 130
    Range("F6:H48").NumberFormat = "0.000"
Next

'this section is supposed to add an = sign in front of the cell contents but doesn't work.
Dim Cell As Range
For Each Cell In Range("F6:H48")
    Cell.Value = "=" & Cell.Value
Next Cell
    
'this section works to highlight the first cell
Worksheets("BOM").Cells(1, 1).Select
       
End Sub

str1 = trim(替换(str1, "0.", "."))

如果处理较新的动态数组功能(vers. 2019+,MS365),您可能会一次性将结果写入整个原始范围(目标范围),如下所示(覆盖现有范围;否则定义一个给定的偏移量来标识另一个目标范围:rng.Offset(,n)=..).

提示:在测试之前制作备份副本(因为它会覆盖 rng)!

请注意,此示例假定 " 字符(asc 值为 34)。

A) 首先尝试通过表格 VALUE() 公式求值

警告:通过 VALUE() 转换空白将写成 #VALUE! 结果,这需要进一步循环。为避免这种情况,您可以在公式 myFormula = "=VALUE(SUBSTITUTE(" & """0""&" & rng.Address & ","""""""",""""))" so that results would be displayed as zero.

前加一个零
Sub ChangeToFractionValues()
'1) define original range to be replaced
    Dim rng As Range
    Set rng = ThisWorkbook.Worksheets("BOM").Range("F6:H48")
'2) define tabular formula
    Dim myFormula As String
    'myFormula = "=VALUE(SUBSTITUTE(" & rng.Address & ","""""""",""""))"
    'Alternative to avoid #VALUE! displays for blanks:
    myFormula = "=VALUE(SUBSTITUTE(" & """0""&" & rng.Address & ","""""""",""""))"
    'Debug.Print myFormula
'3) overwrite original range (otherwise code an offset rng.Offset(,n).Value = ...
    rng.Value2 = rng.Parent.Evaluate(myFormula)
End Sub

根据评论得出结论:

虽然速度很快,但这种方法有一个很大的缺点:Excel 解释 date-like 数字,通过 [=56= 在内部将它们转换为日期] 在此处输入数字部分,因此 3/4" 的单元格输入将 return 对应的当年 3 月 4 日的日期值。


B) 基于循环中直接单元格计算的重写代码 //编辑

与上述处理类似,此方法也基于评估,但将所有 公式 收集为变体数据字段数组 v 中的字符串,这允许操作和单独评估每个单元格输入:

Sub ChangeToFractionValues()
'1) define original range to be replaced
    Dim rng As Range
    Set rng = ThisWorkbook.Worksheets("BOM").Range("F6:H48")
'2) assign formula strings to variant 1-based 2-dim data field array
    Dim v As Variant
    v = rng.Formula2
'3) evaluate results in a loop
    Dim i As Long, j As Long
    For i = 1 To UBound(v)
        For j = 1 To UBound(v, 2)
            v(i, j) = Evaluate("0" & Replace(v(i, j), Chr(34), ""))
        Next j
    Next i
'4) overwrite original range (otherwise code an offset rng.Offset(,n).Value = ...
    rng.Value = v
End Sub

我从我的有用函数库中挖出了以下方法。它将表示为小数字符串的数字转换为等效的数字。只需循环遍历需要转换的单元格并调用此方法:

Public Function FractionToNumber(ByVal Value As String, Optional ByVal Digits As Long = 0) As Double
   Dim P As Integer
   Dim N As Double
   Dim Num As Double
   Dim Den As Double

   Value = Trim$(Value)
   P = InStr(Value, "/")

   If P = 0 Then
      N = Val(Value)
   Else
      Den = Val(Mid$(Value, P + 1))
      Value = Trim$(Left$(Value, P - 1))
      P = InStr(Value, " ")

      If P = 0 Then
         Num = Val(Value)
      Else
         Num = Val(Mid$(Value, P + 1))
         N = Val(Left$(Value, P - 1))
      End If
   End If

   If Den <> 0 Then N = N + Num / Den
   FractionToNumber = Round(N, Digits)
End Function

您也可以编写如下代码:

Sub FractionConvertMTO()
    Dim rng As Range
    Dim Arr As Variant
    Arr = Worksheets("MTO").Range("F6:H48")
    For Row = 1 To UBound(Arr, 1)
        For col = 1 To UBound(Arr, 2)
            str1 = Arr(Row, col)
            pos1 = InStr(str1, " ")
            pos2 = InStr(str1, "/")
            If pos2 = 0 Then
                N = val(str1)
                Num = 0: Den = 1
            Else
                If pos1 And pos1 < pos2 Then
                    N = val(Left$(str1, pos1 - 1))
                    Num = val(Mid$(str1, pos1 + 1))
                Else
                    N = 0
                    Num = val(Left$(str1, pos2 - 1))
                End If
                Den = val(Mid$(str1, pos2 + 1))
            End If
            Arr(Row, col) = N + Num / Den
        Next col
    Next Row
    Worksheets("MTO").Range("F6", "H48") = Arr
End Sub