Excel for Macでシェイプテキスト置換ボタンを作る

業務の都合上、自分だけMacユーザーでほかの全員がWindowsとエクセルで画面設計書を作っているという状況が稀によくあります。Mac版のエクセルでワイヤーフレーム的なのを書くのは挙動が重いので苦手ですが、協業する上では仕方がない場合もあります。

さて、画面の絵の上によくシェイプテキストを乗っけて注釈やIDを付けることがありますが、シェイプテキストは標準の検索置換機能には対応していません。これを実現するにはVBAが必要ですが、ありがたいことに既にQiitaに記事がありました。

- [図形内の文字を置換するExcelマクロ - Qiita](https://qiita.com/Umaremin/items/da717281af8481b4696b)

上記の記事を参考にMac版のエクセルでツールバーから使えるシェイプテキスト置換機能を作ってみました。

## 使い方

オリジナルのコードはセル内で呼び出す関数でしたが、これをリボンから呼び出す機能に変更しています。
1つ〜複数のシェイプが選択中である場合は、そのシェイプだけを対象に置換。
シェイプ未選択の場合はシート内の全シェイプを対象に置換します。

1. ツールバーボタンを押すと入力欄が出るので、カンマ区切りで`検索文字,置換文字`の形式で入力  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48238/f6ff87bd-7f58-f119-f5e6-1da81a8c37d4.png)
    - 検索・置換文字自体に半角カンマが含まれる場合は`\,`でエスケープ   

2. キャンセルを押したり、入力文字にカンマが無かったりするとメッセージが出て終了  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48238/c3217d4b-ae93-8008-ff39-6ce49fbcc376.png)

3. 問題なければシェイプテキストが置換されます
    - 選択中のシェイプがない場合: シート内のすべてのシェイプが置換の対象になります
    - 選択中のシェイプがある場合: 選択されているシェイプだけが置換の対象になります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48238/cd626e4b-2013-5031-3db2-aa054d64d72e.png)

### コード

```vb
Sub ReplaceShapeText()

  Dim sh As Shape
  Dim userInput As String
  Dim findStr As String
  Dim repStr As String
  Dim commaEscape As String
  Dim commaEscapePtn As String
  
  commaEscape = "\,"
  commaEscapePtn = "%%COMMA%%"

  userInput = Application.InputBox("Please input search text and replace text with a comma. Use /, to escape comma.  Example) find,replace")
  userInput = Replace(userInput, commaEscape, commaEscapePtn)
    
  If Len(userInput) < 3 Or InStr(userInput, ",") = 0 Then
    MsgBox ("Your input does not fill the requirement. Quit the execution.")
    Exit Sub
  End If
  
  findStr = Split(userInput, ",")(0)
  findStr = Replace(findStr, commaEscapePtn, ",")
  
  repStr = Split(userInput, ",")(1)
  repStr = Replace(repStr, commaEscapePtn, ",")
  
  If TypeName(Application.Selection) <> "Nothing" And TypeName(Application.Selection) <> "Range" Then
  
    For Each sh In Selection.ShapeRange
      If sh.TextFrame2.HasText = msoTrue And sh.Type <> msoGroup Then
        Call sh.TextFrame2.TextRange.Replace(findStr, repStr)
      End If
    Next
      
  Else
    
    For Each sh In ActiveSheet.Shapes
      If sh.TextFrame2.HasText = msoTrue And sh.Type <> msoGroup Then
        Call sh.TextFrame2.TextRange.Replace(findStr, repStr)
      End If
    Next
 
 End If

End Sub

```

### リボンへの登録方法

最初VBAの使い方が全く分からなかったので詳しめに記載。

0. ファイルを全て閉じる
1. 適当な新規ブックを作成する
2. メニューの「ツール > マクロ」から、Visual Basic Editorを開く
3. 左のツリーから"This Workbook"をダブルクリックしてコードをペースト
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48238/9c6d507d-e2f2-7ccb-9185-c7288825286f.png)
4. ブックを Excel Add-in 形式で保存  
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48238/7a01c788-cddf-6ea3-f11e-d055c40499c8.png)
5. メニューの「ツール > Excelアドイン…」を選択（「挿入 > アドイン」ではないので注意）
6. 先程保存した拡張子が`.xlam`のファイルを一覧に登録し、チェックボックスを付ける  
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48238/d1ecefef-fe3d-d435-0e38-34d1bcb54acb.png)
7. メニューの「Excel > 環境設定」を開き、リボンのカスタマイズ画面へ移動する
8. 左側のプルダウンを「マクロ」に変更し、適当なリボンにボタンを追加する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48238/24551232-f98d-8d5d-7a16-fba2393200f9.png)


## 感想・ハマったところ

- **Excel for Macが日本語に弱い**
    - Visual Basic Editor上で日本語が使えない。無理やりペーストすると ????? になってしまう
    - `InputBox`では日本語を受け取れない
        - なぜか `Application.InputBox` では受け取れる
- `sh.TextFrame2.TextRange.Text`にアクセスしようとするとたまにエラーで止まる
    - シェイプがグループ化されていることが原因だったので、`sh.Type <> msoGroup`からグループでないことを判定するようにした
- **Excel for Macが正規表現に非対応**
    - 「正規表現化したらめっちゃ便利じゃん!」って思ったけどMac版のVBAは未対応だった
    - [【Excel】シート内のシェイプの文字列を正規表現で置換する - Qiita](https://qiita.com/11295/items/de6f3c2b8ac4dcf1d825)
    - [メモ：Excel for Mac のマクロは正規表現を使えない - 駆け出し女流エンジニアブログ@回復中](http://mamecafe.hatenablog.com/entry/2018/03/31/224952)
    - [RegEx with Excel VBA on Mac - Stack Overflow](https://stackoverflow.com/questions/27344932/regex-with-excel-vba-on-mac)

### 仕様です

- 置換に成功したシェイプの書式が外れる!
    - 普通のセルの置換でも外れてしまうので標準的な挙動
    - 1文字づつ書式をコピーして書き戻す実装は書けるっぽい
        - [【VBA】セルの書式を変えずにReplaceする方法 | Know-How-No-Life](https://www.banana-juice.com/tech/articles/replace-without-format)
- マクロを実行したあとに元に戻す(Cmd+Z)ができない!
    - エクセルの仕様なので注意するしかなさそう
    - [【Excel】元に戻す(アンドゥ・Ctrl+Z)が使えない原因 | すまおじ.com](http://sumaoji.com/excel-undo-tukaenai-8893)