2016-08-05 11 views
1

これを行う方法について説明しているトピックをいくつか読みましたが、これはうまくいくものの、非常に遅いでしょう。説明はここにある:Excel VBA:数値フィールドから数字以外の文字を削除しないでください

https://www.extendoffice.com/documents/excel/651-excel-remove-non-numeric-characters.html

これは、範囲内の各セルを反復処理して、フィールド内の文字を反復して、彼らは[0-9]と一致しない場合は、それらを除去することを含みます。誰かが他のより効率的な提案をしているかどうかを見たいと思っていました。

セルの内容を配列にロードし、それを反復し、各エントリを反復するためにそれ自身の配列に分割することです。

+0

ループなしで何を正確に繰り返しますか? – Comintern

+0

セルをループすることは避けられませんが、文字をループする必要はありません。正規表現を使用するだけです:http://stackoverflow.com/a/22542835/4721734もちろん、パフォーマンスを向上させるために配列に範囲をロードすることもできます。 –

+0

@MátéJuhász - 正規表現の置き換えがバイト配列にどのように爆発するのかを知りたいのは興味があります。 ... – Comintern

答えて

2

物事のVBA側(ループに注意してください)では、私はいくつかの異なる方法のパフォーマンスについて私自身の好奇心を満たすことに決めました。それらのすべてが範囲をアレイにプルし、その場所で作業します。リンクされた記事は、によっていずれかでスピードで殺されます。これは単セル値の読み取りと書き込みのオーバーヘッドが原因です。私はRegExp.Replaceを使用する第二の方法について

Private Sub MidMethod(values() As Variant) 
    Dim r As Long, c As Long, i As Long 
    Dim temp As String, output As String 

    For r = LBound(values, 1) To UBound(values, 1) 
     For c = LBound(values, 2) To UBound(values, 2) 
      output = vbNullString 
      For i = 1 To Len(values(r, c)) 
       temp = Mid$(values(r, c), i, 1) 
       If temp Like "[0-9]" Then 
        output = output & temp 
       End If 
      Next 
      values(r, c) = output 
     Next 
    Next 
End Sub 

:第一の方法について

は、私は、 "ビット" linked articleからのコードを最適化された最後の方法は、

Private Sub RegexMethod(values() As Variant) 
    Dim r As Long, c As Long, i As Long 

    With New RegExp 
     .Pattern = "[^0-9]" 
     .MultiLine = True 
     .Global = True 
     For r = LBound(values, 1) To UBound(values, 1) 
      For c = LBound(values, 2) To UBound(values, 2) 
       values(r, c) = .Replace(values(r, c), vbNullString) 
      Next 
     Next 
    End With 
End Sub 

最後I Byteアレイを使用:

Private Sub ByteArrayMethod(values() As Variant) 
    Dim r As Long, c As Long, i As Long 
    Dim chars() As Byte 

    For r = LBound(values, 1) To UBound(values, 1) 
     For c = LBound(values, 2) To UBound(values, 2) 
      chars = values(r, c) 
      values(r, c) = vbNullString 
      For i = LBound(chars) To UBound(chars) Step 2 
       If chars(i) > 47 And chars(i) < 58 Then 
        values(r, c) = values(r, c) & Chr$(chars(i)) 
       End If 
      Next 
     Next 
    Next 
End Sub 

1000個の細胞、それぞれが25の文字と数字のランダムなミックスを含むに対するベンチマークそれらをする編このコード:

Private Sub Benchmark() 
    Dim data() As Variant, start As Double, i As Long 

    start = Timer 
    For i = 1 To 5000 
     data = ActiveSheet.Range("A1:J100").Value 
     MidMethod data 
    Next 
    Debug.Print "Mid: " & Timer - start 

    start = Timer 
    For i = 1 To 5000 
     data = ActiveSheet.Range("A1:J100").Value 
     RegexMethod data 
    Next 
    Debug.Print "Regex: " & Timer - start 

    start = Timer 
    For i = 1 To 5000 
     data = ActiveSheet.Range("A1:J100").Value 
     ByteArrayMethod data 
    Next 
    Debug.Print "Byte(): " & Timer - start 

End Sub 

結果が恐ろしく驚くことではなかった - 正規表現の方法は、これまでによって(最速ですが、それらのどれも私が)「高速」呼びたい何をしない:私はこれは私が私のテストハーネスを介して実行できないというSiddharthRoutのクール式メソッド@と比較する方法が分からない

Mid: 24.3359375 
Regex: 8.31640625 
Byte(): 22.5625 

注意。 www.extendoffice.comのコードも実行されている可能性が高いので、私はテストしませんでした。

+1

@brettdjと私はこの議論を数年前に行い、それをテストしました... MidはRegExよりも遅く、大規模なデータセットでテストすると顕著に気づくことができます。 –

+0

@SiddharthRout - 私は、バイト配列のパフォーマンスが低いことにもっと驚きました。私は 'Chr $(chars(i))'を 'chars(i)-48'に置き換えて数秒を削ることができますが、文字列のコンカットからメモリをコピーすることはすべてパフォーマンス上のボトルネックになっているようです。 – Comintern

+0

データセットで数式をテストしてください。 1つのセルに入力し、最初のセルの右下をダブルクリックして自動入力します。 1000セルを計算するのに要する時間は約何秒ですか? –

2

VBAまたはルーピングの必要はありません。 の式は、あなたが望むものを達成することができます。

=NPV(-0.9,,IFERROR(MID(A1,1+LEN(A1)-ROW(OFFSET(A$1,,,LEN(A1))),1)%,"")) 

これは配列式です。あなたはCtrlキー + Shiftキー + は、Enterキーを押す必要があり

enter image description here

説明

各用語はnnth用語がである(1+rate)^nの逆、乗算されシリーズ。

レートに異なる値を使用することによって、異なる結果が得られます。この場合、-0.9を使用すると、​​となります。

Result: {0.1;0.01;0.001;0.0001;0.00001} 
Inverse of above: {10;100;1000;10000;100000} 
Also NPV skips text values which contributes to the above 

免責事項:私はこの式を思い付くしませんでした。私はこの式をずっと前から見ていただけで、それに恋していました。それ以来、私のデータバンクの一部となっています。

関連する問題