2011年12月25日日曜日

[ExcelVBA] 税込み価格への修正


■お題
税込み価格への修正(問題出典:どう書く?org)
- 問題詳細 -
ここにチラシの原稿があります。例えば「ダイコン150円、ハクサイ120円、ジャガイモ30円」のような文字列です。法改正によって商品の値段は税込み表示にしないといけなくなりました。そこで、与えられた文字列の中から税抜き価格を見つけ出し、税込み価格に変更した文字列を返す関数を作ってください。
なお、税抜き価格は半角の数字の連なりで、かつ半角の数字の連なりはすべて税抜き価格だとします。「9,800円」「百円」「100円」「100g80円」などのような記述はないと考えてかまいません。 また税込み価格は税抜き価格の1.05倍で、端数は切り捨てとしてください。

■解答例
正規表現を使う問題ですね。
問題文は、親切でとてもやさしいものとなっています。
他の言語であれば置換する時にマッチしたデータに対し計算を施した結果を置換することができるのに
対しExcelVBAではできないようなので、ちょっと発想の転換が必要なのかもしれません。


では、コードです。
Option Explicit

Function ExchangeValue(Str As String)
    Dim Reg As Object, result As Object
    Set Reg = CreateObject("VBScript.RegExp")
    
    Reg.Pattern = "\d+"
    Reg.Global = True
    
    Set result = Reg.Execute(Str)
    Dim i As Integer
    For i = result.Count - 1 To 0 Step -1
        With result.Item(i)
            Str = Left(Str, .FirstIndex - 1) & Replace(Str, .Value, CInt(.Value) * 1.05, Start:=.FirstIndex)
        End With
    Next
    
    ExchangeValue = Str
End Function
3行目:引数に変更する文章をうけとるStrを用意してあります。
4行目:変数Regは正規表現のオブジェクトを格納するよう。
変数resultは、正規表現の結果を格納するよう。
5行目:正規表現のオブジェクトを生成

7行目:正規表現を指定。今回は「数字が1つ以上続く」を指定
8行目:複数回出てくることを想定してGlobalプロパティをTrue

10行目:正規表現の結果を格納
11行目:変数i For文内で配列のインデックスとして使用
12行目:For文:マッチした正規表現の回数文ループ。
13行目:正規表現の結果のオブジェクトが長かったんで、Withでくくりだしています。
End Withまでは、以降 .で始まる文字列は、result.Item(i)が省略されてます
14行目:Replace関数の引数にStartオプションを使うとそれより前の文字列は返されません。
よって、全文取得するため、Startオプションより前をLeft関数で取得しています。
Replaceする内容は、10行で実行した正規表現の結果をもとに連続する数字を
1.05倍したものと置換していきます。
15行目:Withを終了
16行目:繰り返し

18行目:変換した文字列を返す

実際にこんな感じで使う
Option Explicit

Sub main()
    Dim Str As String
    Str = "「ダイコン150円、ハクサイ120円、ジャガイモ30円」"
    
    Debug.Print ExchangeValue(Str)
End Sub


実行結果
「ダイコン157.5円、ハクサイ126円、ジャガイモ31.5円」

0 件のコメント: