正規表現で文字列中に出現する複数の数値文字列を置換する

以下はyahoo知恵袋より正規表現の質問を抜粋したもの。思いのほか難しかったので、対応方法を備忘録として残す。
まず、質問内容は以下。

エクセルのZ列にx-1A,x-47B,xx-234D,xx-12のようなデータが複数存在します。
このデータを以下のように変更したいです。
x-001A,x-047B,xx-234D,xx-012
-の後に数字3桁に統一して他は何も変更しません。

以下のロジックで実現可能。

  1. 文字列をカンマ区切りで分割しリストとする
  2. リストから要素を1個ずつ取り出し、以下を繰り返す
    2-1. 正規表現 [0-9]+ により、処理中の要素から数値部分を取り出す
    2-2. 数値部分をゼロ埋めして3桁にする
    2-3. 処理中の要素に対し2-1で取り出した値で検索して2-2の値で置換。その結果を別途用意した置換後リストに格納
  3. 置換後リストをカンマ区切りで結合し、元の文字列と置き換える

◆Pythonの場合

 1import re
 2text = "x-1A,x-47B,xx-234D,xx-12"
 3repLst = []
 4regex = r'[0-9]+'
 5lst = text.split(',')
 6for elem in lst:
 7  numStr = re.search(regex, elem).group()
 8  num = int(numStr)
 9  pad = f'{num:03}'
10  repLst.append(elem.replace(numStr, pad))
11print(','.join(repLst))

◆Javaの場合

 1import java.util.ArrayList;
 2import java.util.List;
 3import java.util.regex.Matcher;
 4import java.util.regex.Pattern;
 5
 6public class Main {
 7  public static void main(String[] args) {
 8    String text = "x-1A,x-47B,xx-234D,xx-12" ;
 9    String regex = "[0-9]+" ;
10    Pattern p = Pattern.compile(regex);
11    Matcher m;
12    String numStr, pad;
13    int num;
14    List<String> repLst = new ArrayList<String>();
15
16    String[] lst = text.split(",");
17    for(String elem : lst){
18      m = p.matcher(elem);
19      if(m.find()){
20        numStr = m.group();
21        num = Integer.parseInt(numStr);
22        pad = String.format("%03d", num);
23        repLst.add(elem.replace(numStr, pad));
24      }
25    }
26    System.out.println(String.join(",", repLst));
27  }
28}

◆Excel VBAの場合

 1Sub test()
 2  Dim str, text
 3  text = "x-1A,x-47B,xx-234D,xx-12"
 4
 5  Dim regex, m
 6  Set regex = CreateObject("VBScript.RegExp")
 7  regex.Pattern = "[0-9]+"
 8  regex.Global = True
 9
10  Dim lst, elem, repLst(), i, numStr, pad
11  lst = Split(text, ",")
12  i = 0
13  For Each elem In lst
14    Set m = regex.Execute(elem)
15    If m.Count > 0 Then
16      If i = 0 Then
17        ReDim repLst(i)
18      Else
19        ReDim Preserve repLst(i)
20      End If
21      numStr = m(0).Value
22      pad = Right("000" & numStr, 3) ' ゼロ埋め 
23      repLst(i) = Replace(elem, numStr, pad)
24      i = i + 1
25    End If
26  Next
27  Debug.Print Join(repLst, ",")
28  Set regex = Nothing
29End Sub

これらのコードの実行結果は、期待どおりに x-001A,x-047B,xx-234D,xx-012 となる。

関連ページ