2016/6/11更新その2
If cells(rng.row,rng.column).Value = cells(rng.row,rng.column).Formula Then isFormula2010 = True Else isFormula2010 = False
からさらに
If Rng.Value = CStr(Rng.Cells.Formula) Then isFormula2010 = False Else isFormula2010 = True
変更しました
変更前だと反対です
Function isFormula2010(Rng As Range) As Boolean
If Rng.Value = CStr(Rng.Cells.Formula) Then isFormula2010 = False Else isFormula2010 = True
End Function
Reliefさんの記事はobjCellなんですけど、こちらはレンジ型にして、結合セルでも対応できるようにしてあります。
この関数はrangeに数式が入っていたらTrue、それ以外はFalseを返します。
(追記)なぜそうしていたのか理由を思い出しました。Cells().formulaじゃないと数式を吐かないことがあるのでした。なので訂正します。もとは、
If Rng.Value = Rng.Formula Then isFormula2010 = True Else isFormula2010 = False
Range.Formulaは式の値が出るときと出ないときがあるみたいです。なのでrngをセルに分解します。
しかしEXCEL2010だけか?range.cells.Formulaプロパティをみつけたのでこれを使うと簡単になりました。
もしこれが使えないときは
Function isFormula2010(Rng As Range) As Boolean
If Rng.Value = CStr(Rng.Formula) Then isFormula2010 = False Else isFormula2010 = True
End Function
を使ってください。この場合はあとで検索で数式を探して確認してください。
EXCEL2013以降はisformulaの出番ですがWorkSheetFunctionを噛ませないとだめみたいです。(というか range.HasFormulaを使うか...)
'EXCEL 2013 Later
Function isFormula2013(rng As Excel.Range) As Boolean
If Excel.WorksheetFunction.IsFormula(rng) = True Then isFormula2013 = True Else isFormula2013 = False
End Function
これはなぜ作る必要性があるのか。それは上記のとおりEXCEL2013で新しくisFormulaが作られてしまったからなのです。
なので旧バージョンと混在している環境では、isFormulaではなくisFormula2010を作る必要があります。
この関数の必要性
この関数はお仕事で人に渡すEXCELから数式を消すときに使います。
複数のファイルから値を引っ張ってこれるEXCELですが、さすがに人に渡してはどうしようもないですね。
なのでこれで式を消すわけです。
Sub DeleteExcelFunctionWithMerging()
'Merge Cells is still Merge
'アクティブシートにおいて、結合セルは結合を維持したまま式を消去します
'QIIQ From Qiita
Dim wb As Excel.Workbook: Set wb = ThisWorkbook
Dim ws As Excel.Worksheet: Set ws = ActiveSheet
Dim str As String
Dim Urng As Range
Dim Rng As Range
Dim v
If MsgBox("警告:このVBAマクロはアクティブシートの式をすべて値に変えてしまいます。" & vbCrLf & "This Macro change active Sheet Formula to value." & vbCrLf & "実行する場合はOKを、違う場合はキャンセルをクリックしてください。" & "If you do not run this Macro, Click Cancel", vbCritical + vbOKCancel, "警告 Warning") = vbCancel Then Exit Sub
Set Urng = ws.UsedRange
For Each Rng In Urng
If isFormula2010(Rng) Then
v = Rng.Value
Rng.Value = ""
Rng.Value = v
End If
Next
End Sub
Function isFormula2010(Rng As Range) As Boolean
If Rng.Count = 1 Then
If Rng.Value = CStr(Rng.Cells.Formula) Then isFormula2010 = False Else isFormula2010 = True
Else isFormula2010 = False
End If
End Function
さてこの式の意味ですけど
rngに式が入っている場合、
=1+1だと
rng.value は計算結果2
rng.Cells.formula は=1+1
が返ります。
するとこれが一致するときは、式が入っていないときだということになります。
パソコン裏技道場さんは
If Cstr(rng.value)<>Cstr(rng.Formula)
ってしているけど、文字列に変換するCstrはたぶん要らないと思う。~~ VBAは自動的に型変換するのでCstrで明示する場合が思いつきません。~~思いついたりなにかあれば変えます。Formulaだけはなぜか関数に突っ込んだとき型変換しないときがあるので、式の方だけCSTRをいれました。
とりあえず当方ではこんな感じで動かしています。
あ、上の方のSubの方ですか?
アクティヴシートを指定してUsedrangeを取得してFor Each でUsedRangeのセル(結合を想定してRangeにしている)を確認して数式があったら、一度値を取得して、式を""で消してから値を入れるというものです。
クリアコンテンツが結合していると効かないのでこうなります。
rng.clearcontentsにしてみろ動かないから。
あと、A1:Z40みたいにRangeを設定して関数にぶち込むと動かないとか嫌がらせとみなすから。あとVariantはas Variantなんて書くわけがないだろう。v一個で十分なんだよ。
は、つい言葉がきつくなってしまいました。いろいろな信じがたいことをする人がいるので。まあそれは自分みたいです。
Function isFormula2010Strong(rng As Excel.Range) As Variant
If rng.Count = 1 Then
If rng.Value = CStr(rng.Cells.Formula) Then isFormula2010Strong = True Else isFormula2010Strong = False
Else
isFormula2010Strong = CVErr(Excel.xlErrRef)
End If
End Function
IsFormlaで数式ではない場合エラー処理をすると返る型はVariantになります。
強化型なので修飾子も使いました。
おわりに
この関数はおおむね、
For Each v In Worksheets(1).UsedRange
If isFormula2010(r) Then
こんな展開以外はないと思います。
なのは間違いないでしょう。
2008.05.15 Thursday
セルが数式かどうかを調べる技じゃ。ちと高等じゃぞ!-パソコン裏技道場
ISFORMULA 関数
ISFormula関数
Range.Cells Property (Excel)
Range.HasFormula プロパティ
配列数式かどうかを判定する