[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『正規表現を使って0埋めパディング しコードの安定性を確保したい』(かず)
正規表現を使って0埋めパディング
しコードの安定性を確保したい
最小1桁最大3桁の自然数の文字列を左0埋め
パディングしたいです。
例えば
1→001
99→099
としたいです
桁数が固定で
Dim s AS string
s = right("000" & s, 3)
のようなコードをよ時々使っています。
今般、古いURLを新しいURLに変換する必要に
迫られ、繰り返し処理が必要なので正規表現を
使って対応する必要があります。
ゆくゆくマクロでシートに記載した正規表現の文字列を
与えて、ExecuteやReplace メソッドで使おうという
方向です
1.現状のコード
Dim reg As Object Dim s As String
Set req = CreateObject("Microsoft.XMLHTTP") Set reg = CreateObject("VBScript.RegExp")
With reg .Global = True ' ◆ .Pattern = "(\d{1,3}\b)" '\d数字が最小1桁最大3桁 ' \b終りが空白やタブ単語の切れ目 ' ()でグルーピング 後で$1として使用 s = .Replace(s,"000$1") .Pattern ="\d+(\d{3}$)" '000d〜000ddd (\d)$で後ろから3桁数字 ’をグルーピング s = .Replase(s, "$1") End With
としました。これで sが55なら 055にゼロ埋め可能です。 (これだけならRight関数の方が単純でいいでしょう...)
2.改善案?
ゼロ埋めして合わせたい桁数nを、定数ではなく変数として
引数で与えたいです。
.Pattern = "(\d{1,n}\b)" ' 最大N桁
s = .Replace(s,"0000000$1") ' 左の0の個数>N の個数
'となるよう十分にゼロ埋め
.Pattern ="\d+(\d{N}$)" ' 実際にはNは変数として扱われていない。 s = .Replase(s, "$1")
s = .Replace(s,"000000$1")
.Pattern ="\d+(\d{N}$)" ' 000d〜000dddを(\d)$で後ろN桁を識別 s = .Replase(s, "$1") 上のように 正規表現に変数として桁数を指定できる ようにする方法をご存知の方が入ましたら是非教えてください
< 使用 Excel:Excel2016、使用 OS:Windows10 >
Sub Sample() Const MySTR As String = "123"
Debug.Print "5桁" Debug.Print String(5 - Len(MySTR), "0") & MySTR Debug.Print WorksheetFunction.Rept("0", 5 - Len(MySTR)) & MySTR
Debug.Print vbCrLf
Debug.Print "3桁" Debug.Print String(3 - Len(MySTR), "0") & MySTR Debug.Print WorksheetFunction.Rept("0", 3 - Len(MySTR)) & MySTR
End Sub
【参考】
http://www.moug.net/tech/exvba/0140035.html
(もこな2) 2018/05/11(金) 09:36
>.Pattern = "(\d{1,n}\b)" ' 最大N桁 これだと、長さが n か n以上の数値の末尾の n桁の数値が対象になりますよ?
サンプル
Sub test() MsgBox GetFormatNumber("avc12ccc2" & vbCrLf & "12aaa2ddd12345", 3) End Sub
Function GetFormatNumber(ByVal txt As String, ByVal n As Long) As String Dim i As Long, mtch As Object, m As Object With CreateObject("VBScript.RegExp") .Global = True: .MultiLine = True .Pattern = "(^|\D)(\d+)(?=\D|$)" Set mtch = .Execute(txt) If mtch.Count Then For i = mtch.Count - 1 To 0 Step -1 Set m = mtch(i) txt = Application.Replace(txt, m.firstindex + Len(m.submatches(0)) + 1, _ Len(m.submatches(1)), Format$(m.submatches(1), String(n, "0"))) Next End If End With GetFormatNumber = txt End Function
(seiya) 2018/05/11(金) 11:48
■seiya さんのコード
"(^|\D)(\d+)(?=\D|$)" の (?=\D|$) の意味は
正規表現の構文
https://msdn.microsoft.com/ja-jp/library/cc392020.aspx に "Windows(?=95|98|NT|2000)" は "Windows2000 " の "Windows" には一致しますが、"Windows3.1" の "Windows " には一致し ませんとありどうにか理解できました。
(\d+)(?=\D|$) は \d+で 1個以上の数字 例 12345
に続いて \D 数字以外か$ 行末 があるときパターンに一致
と言う意味ですね。
これが
1番目のグループ(^|\D) 行頭か数字以外の文字
2番目のグループ(\d+)(?=\D|$) 1個以上数字で、数字以外か行末が続く
としてExecuteメソッドで得られるmtchオブジェクトで、mtch.Count +1 個
それぞれで2つのSubmatchesプロパティが得られる
マッチングした箇所をmtch(i)→mとして (mtch.Count -1) から0 まで
ループでnで指定された桁数でゼロ埋め処理を行う
ループをmtch.Count -1から0までmtch(i)を後方から処理するのはtxtを後ろから
処理=マッチングで検知した文字列をリプレース関数で別の文字列に置き換えるの
ことを考慮している 例えば10文字目から2文字の数字を0埋めして3文字にしたら、 今までの12文字目は13文字目の位置になるので、Executeメソッドで得られた夫々の
数字の箇所の位置 m.firstindexを利用するため。
mのsubmatchesは最初に指定した2個のグループで引数は最初0と1で扱う
ワークシート関数 REPLACE(元の文字列,開始位置,文字数,置換文字)なので
元の文字列 txt
開始位置 m.firstindex+len(m.submatches(0)) +1 → 今処理しているマッチング箇所が ・・2ddd12345 の所なら m.firstindex は2の所 dddが submatches(0) 12345が submatches(1) なので m.firstindex + Len(m.submatches(0)) + 1 が変更の開始位置 文字数 : 12345の長さlen(submatches(1)) 置換文字: Format$ は戻り値がStringと明示したFormat関数 gogle でWebサイト調べましたが解説見つからず 結局エクセルの学校に戻ってseiyaさんの解説見つけました。 この場合はformat関数のままでも問題なかったです 戻り値がFormat関数の戻り値variantのままだとエラー になったりすることもあるのでしょうか?
Sting(n,"0") はn個の"0"なので
m.submatches(1)を n個"0"の形で整形 これをReplace関数で処理ということですね 実機で試してみるとnが処理対象の数字列より小さいとFormat関数は 何もしないので、例えば n = 1 の時 ddd12345の12345 は12345 のまま 他の数字も同様。 振り返ってみると n桁の数字にゼロ埋めすると言うとき現状の数字 データの桁数がそうなっているかは意識していなくて、処理の手順 のイメージが数字の前に"0"をつければいいとしか考えていませんでした 単に3桁ゼロ埋めにしようと言うとき、3桁未満はこうする、3桁以上は そのままなのか、切り詰めるのかなど明確にしてからコード化しない といけないのですね。要求仕様を吟味して設計して実装しないと手戻り してしまうと認識しました。
本当に色々と勉強になりました。
ちなみに皆さんは、コードに注釈を書かないのは単に投稿なので入れて
いないだけであって、ご自分のお仕事で他の人が保守するツールのコード
にはコメントを入れていらっしゃるのでしょうか?
今回 正規表現 を使ったコードを初めて書いて、パターンの書き方など
勉強して、自分でも2、3月もすれば細かいルール忘れてしまうと思いました
自衛策としてツールに逐次的にコメント書いておこうと思った次第です
皆さんはどのようにされているか参考に教えて頂ければ助かります
以上
(かず) 2018/05/13(日) 00:44
> ちなみに皆さんは、コードに注釈を書かないのは単に投稿なので入れて > いないだけであって、ご自分のお仕事で他の人が保守するツールのコード > にはコメントを入れていらっしゃるのでしょうか?
仕事上は別ですが、掲示板では理解しようとする気のない人に無駄な労力は使いたくないので、 提示されたコードの関して詳細な質問が追加投稿された場合、その都度コメントするようにしています。
ちなみに 正規表現で ()内の最初が?で始まる場合は後方参照から除外されます。 (?=xx) xxのみにマッチ (?!xx) xx以外にマッチ (?:xx) xxのみにマッチ (私はあまり使用しません。)
なのでマッチした文字列からは除外されます。
(seiya) 2018/05/13(日) 10:03
コメントありがとうございます
教えて頂いたコードと
正規表現パズル
http://www.geocities.jp/oraclesqlpuzzle/regex/
と言うサイトの 6-5 IPアドレスの左に0埋め
という以下のロジック
select Val as beforeIP,
RegExp_Replace(RegExp_Replace(Val,'([0-9]+)','000\1'),
'0*([0-9]{3})','\1') as afterIP を見て、これであれば私が最初に考えていた方向とおなじだなと 思い教えて頂いたコードを以下のように変更してみました
Sub test2() MsgBox GetFormatNumber("avc12ccc2" & vbCrLf & "12aaa2ddd12345", 1) End Sub
Function GetFormatNumber(ByVal txt As String, ByVal n As Long) As String Dim i As Long, mtch As Object, m As Object Dim reg As Object Dim RpPtn As String
Set reg = CreateObject("VBScript.RegExp") With reg .Global = True: .MultiLine = True 'この?はグループに続き\Dか$が来た時だけパターンに合致の意味 .Pattern = "(\d+)(?=\D|$)" txt = .Replace(txt, String(n, "0") & "$1")
.Pattern = "\d*(\d{" & n & "})(?=\D|$)" txt = .Replace(txt, "$1")
End With GetFormatNumber = txt
End Function
仕様 m桁の数字をn桁に合わせて左0埋めパディング m<=n の時 左0埋めしn桁 m>nの時は 右揃え としてn = 1,3,6 で動作しました。
自分としてはこれでまず満足です。 話題がそれて恐縮ですが、せっかくそれなりのサブルーチンが を作ったので、個人用マクロ personal.xls とか会社のファイルサーバ 上の共用マクロブックにこのユーザ関数を置いて、別のブックのマクロから 参照設定して利用できるようにすれば便利と考えました
ただ初心者が最初に作ったもので、自分が忘れずに置くためのものですが マクロをブック本体の外に置いて利用するなど、ちゃんとやれるものでしょうか
共用マクロの場所を忘れたり、異動などでマクロの所在が変わると使えなくなる ?等の注意事項、制約事項はないのでしょうか? そういった点見通しについて ご経験ありましたらぜひ教えてください
以上
(かず) 2018/05/14(月) 03:17
AddInにすればよいのでは? 検索すれば色々出てくるはずです。
その関数はMacでは使用できませんよ? (seiya) 2018/05/14(月) 11:31
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.