質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

Office 365

Office 365は、マイクロソフトが販売している企業向けクラウドベースのグループウエアサービス。電子メールや予定表、Webサイト構築、オンラインストレージ、ビデオ会議などビジネスで必要な機能を備えています。クラウドサービスのため、自社での専用サーバーの設置の必要がないことが特徴です。

Q&A

解決済

2回答

1780閲覧

VBAで、For/If構文内の入れ子構造の一部が頻出する場合、それを1回書くだけにできないか?

hSpringsteen

総合スコア7

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

Office 365

Office 365は、マイクロソフトが販売している企業向けクラウドベースのグループウエアサービス。電子メールや予定表、Webサイト構築、オンラインストレージ、ビデオ会議などビジネスで必要な機能を備えています。クラウドサービスのため、自社での専用サーバーの設置の必要がないことが特徴です。

0グッド

0クリップ

投稿2019/12/28 11:05

編集2019/12/28 12:05

前提・実現したいこと

パワーポイント(for Mac 2016)において、全スライド・オブジェクトに対して、テキスト検索・変換するコードを作成しています。
反復して同一の構文を書かなければいけない部分を、なんとか1回の記載で済むようにできないかと模索しています。
少しわかりにくいですが、マクロのVBAで、For構文、If構文内の入れ子構造の下層(中身)部分が、
並列するFor/If構文の下層と共通しており、
かつ今後の経過で下層部分のみ書き換える可能性が高い場合、
同一構文は1回書くだけにした方が効率的です。

具体的には、以下の通りです。

該当のソースコード

VBA

1Option Explicit 2Sub 下付き文字にするコード例() 3Dim pos As Long 4Dim Strnum As Long 5Dim RepList() As Variant 6Dim sld 7Dim shp 8Dim txt As String 9   RepList = Array(“●”, “●”, “●")   10 11For Each sld In ActivePresentation.Slides 12 For Each shp In sld.Shapes 13  If shp.TextFrame.HasText Then ‘通常のテキストボックスの場合 ① 14   txt = shp.TextFrame2.TextRange.Text '元テキスト内容を一旦格納  15   For i = 0 To 2 ‘★ 16    Strnum = 1 17     While InStr(Strnum, txt, RepList(i), vbBinaryCompare) > 0 18     pos = InStr(Strnum, txt, RepList(i), vbBinaryCompare) 19      shp.TextFrame2.TextRange.Characters(pos + 1).Font.Subscript = msoTrue 20     Strnum = Strnum + 2 21    Wend 22   Next i ‘★★ 23  End If 24 25   If shp.HasTable Then ‘テーブル内の場合 ② 26        For Each clm In shp.Table.Columns 27             For Each cl In clm.Cells 28                txt = cl.Shape.TextFrame2.TextRange.Text 29                     上記★〜★★が共通 30                Next cl 31            Next clm 32    End If 33 34 Next shp 35Next sld 36End Sub

①変換対象がテキストボックス内の場合と、②表テーブル内のセルで場合とで、中身の動作は★〜★★で共通しています。
その★〜★★部分のみ今後変更する可能性がある場合、書き換える部分が多いほど煩雑になるし、構文エラーのリスクも高まります。

試したこと

浅学ですが、Call構文→Private Sub()で
★〜★★部分を抽出してみましたが、
「オブジェクトの指定が必要」などと表示され、Subプロシージャを単純に分けるとうまくいかないようでした。

エラーの種類
・Call→ Private Sub() ()は空欄
→「変数が定義されていません」
・Call→ Private Sub(ByVal Strnum As Long, txt As String, RepList() As Variant, pos As Long)
→構文全体が青くなり、エラー表示はされないがエラー音が鳴って何も起こらない
・Call→ Function(ByVal Strnum As Long, txt As String, RepList() As Variant, pos As Long)
→エラー表示はされないが、エラー音が鳴って何も起こらない
・txt = she. 〜〜 をPrivate Subに入れないようにすると、「オブジェクトの指定が必要」のエラーは無くなりました。

補足情報(FW/ツールのバージョンなど)

Mac OS Mojave
Microsoft Office Powerpoint for Mac ver 15.33

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2019/12/28 11:10

共通部分を関数化する方向で良いと思います。
hSpringsteen

2019/12/28 11:18

早速の回答をありがとうございます。 shp.TextFrame2.TextRange.Characters(pos + 1).Font.Subscript = msoTrue部分でテキストを書き換え終了しており、戻り値がないセッティングだと思われますが、 Functionプロシージャで良いのでしょうか? 定義済みの変数は、 Function 共通する部分(pos As Long, Strnum As Long, RepList() As Variant) で記載し、Function内に共通部分を記載、Call構文で呼び出す、という流れでしょうか?
hatena19

2019/12/28 11:21

> 浅学ですが、Call構文→Private Sub()で > ★〜★★部分を抽出してみましたが、 そのコードを質問に追加して、どこで「オブジェクトの指定が必要」のエラーがでるか提示してください。 あと、モジュール先頭に Option Explicit を追加して変数宣言を強制して、使用する変数はすべて宣言するようにしましょう。
meg_

2019/12/28 11:47

Sub()で良いかと思います。エラーは必要な引数が不足していたのではないでしょうか?
hatena19

2019/12/28 12:29 編集

Option Explicit 宣言と変数を必ず宣言して使用するという癖をつけましょう。 引数で渡す変数は、少なくとも shp と txt は必須です。RepList, Strnum, pos, i はSub内で宣言すればいいでしょう。 このヒントでうまくできないなら、現状のコードをすべて提示してどこでエラーが出るかも提示してください。
hSpringsteen

2019/12/28 12:20

CallするプロシージャはFunctionでもPrivate Subでもなく、「Sub 作業部分()」で良いということでしょうか。 引数引き渡しについては、今回のように引用プロシージャ内で作業が完結する(値を返されない)場合、 Callがある部分の上層の変数(sld,shp,txt)を引数とし、作業部分(下層)の変数(i, pos, Strnum, RepList() )は無視する形になりますか? 具体的には Call 作業部分(sld, shp, txt) Sub 作業部分(ByVal sld, ByVal shp, ByVal txt As String) という引数記載になりますか? 上記だと無反応で、ByVal〜部分を消してみると、RepList()の定義が必要、とコメントが出てしまいます
guest

回答2

0

すでにベストアンサーは出ていますが参考・応用編として。

meg_ さんや hatena19 さんの話のとおり、共通部分を別処理にしていることが前提で、
そのうえで、「共通部分」として、今の処理とは全く別の処理もしたくなった場合の話です。

元の処理を残したままで作ろうとすると、再度For/If構文の記述が必要になりちょっと面倒だったり、パターン分けを追加したい場合に修正漏れが出てしまいます。

このような場合には、「処理対象を見つける」と「処理をする」を別にする、という手があります(他の言語では他にも手がありますがMacのVBAだと難しい)。

下記のコードを例にすると、
「処理対象を見つける」がGetTextRange2FromSlide関数になります。
SlideからTextRange2(図形のテキスト)をCollectionとして取得します。
そして、「処理をする」が作業部分2になります。

このようにすることで、「スライド内の図形からテキスト部分を取得する」という処理が抽出でき、他の処理をしたい場合にも使いまわしやすくなったり、対象を追加したい場合(e.g. グループ化された図形)にも、GetTextRange2FromSlideだけを修正すればいい、ということになります。

なお、以下のコードはWindowsで動作確認はしていますが、Macでは一部型宣言がうまく認識されないかもしれません(参照設定依存のため)。

vba

1Sub 下付き文字にするコード例2() 2 Dim pres As PowerPoint.Presentation '`PowerPoint.`は無くても動くはず(以下同様) 3 Set pres = Application.ActivePresentation 4 5 '各スライド毎にループ。 6 Dim sld As PowerPoint.Slide 7 For Each sld In pres.Slides 8 9 'スライド内の`TextRange2`オブジェクトを取得。 10 '`VBA.`は無くても動くはず(以下同様) 11 Dim txtRngs As VBA.Collection '(Of Office.TextRange2) 12 Set txtRngs = GetTextRange2FromSlide(sld) 13 14 Dim tr As Office.TextRange2 '`Office.`は無くても動くはず(以下同様) 15 For Each tr In txtRngs 16 '下付き文字にする 17 Call 作業部分2(tr) 18 Next tr 19 20 Next sld 21 22End Sub 23 24'スライド内から、テキストを持っている図形のTextRange2を取得する。 25Public Function GetTextRange2FromSlide(inSld As PowerPoint.Slide) As VBA.Collection '(Of Office.TextRange2) 26 Dim col As VBA.Collection 'Macでも使えるはずだけど、何か問題があったら`VBA.`を消してみる 27 Set col = New VBA.Collection 28 29 Dim shp As PowerPoint.Shape 30 For Each shp In inSld.Shapes 31 32 If shp.TextFrame2.HasText Then '通常のテキストボックスの場合 ① 33 34 col.Add shp.TextFrame2.TextRange 35 36 ElseIf shp.HasTable Then 'テーブル内の場合 ② 37 38 Dim clm As PowerPoint.Column 39 For Each clm In shp.Table.Columns 40 41 Dim cl As PowerPoint.Cell 42 For Each cl In clm.Cells 43 44 col.Add cl.Shape.TextFrame2.TextRange 45 46 Next cl 47 48 Next clm 49 50 End If 51 52 Next shp 53 54 Set GetTextRange2FromSlide = col 55End Function 56 57Private Sub 作業部分2(inTxtRng As Office.TextRange2) 58 'RepListの後ろの文字を下付き文字にする。 59 Dim RepList() As Variant 60 RepList = Array("●", "●", "●") 61 62 Dim txt As String 63 txt = inTxtRng.Text 64 65 Dim i As Long 66 For i = LBound(RepList) To UBound(RepList) '0 To 2 ではなく、配列の下限・上限から指定した方が修正時の手間が減る。 67 Dim Strnum As Long 68 Dim pos As Long 69 Strnum = 1 70 71 Do 72 pos = InStr(Strnum, txt, RepList(i), vbBinaryCompare) 73 If pos <= 0 Then Exit Do 74 75 inTxtRng.Characters(pos + 1).Font.Subscript = msoTrue 76 Strnum = Strnum + 2 77 Loop 78 Next i 79End Sub

投稿2019/12/29 10:20

imihito

総合スコア2166

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hSpringsteen

2019/12/29 13:34

アドバンスの解説をありがとうございます。取り急ぎコメントしますが、勉強して理解しながら、取り入れていこうと思います。
guest

0

ベストアンサー

まずは、Option Explicit についてWEB検索して意味を理解してください。
そしてOption Explicitをモジュールの先頭に記述して、変数は必ず宣言するようにしましょう。
それをしないとなかなかスキルアップはできないと思います。

コードとしては下記のような感じになると思います。
PowerPointのVBAを書いたことがないので、提示されているコードを単純に分割しただけ、あと変数を宣言するようにしただけです。動作確認はしてませんので、参考にして適宜修正してください。

vba

1Option Explicit 2 3Sub 下付き文字にするコード例() 4 Dim sld As Object 5 Dim shp As Object 6 Dim clm As Object 7 Dim cl As Object 8 Dim txt As String 9 10 For Each sld In ActivePresentation.Slides 11 For Each shp In sld.Shapes 12 If shp.TextFrame.HasText Then '通常のテキストボックスの場合 ① 13 txt = shp.TextFrame2.TextRange.Text '元テキスト内容を一旦格納 14 Call 作業部分(txt, shp) 15 End If 16 17 If shp.HasTable Then 'テーブル内の場合 ② 18 For Each clm In shp.Table.Columns 19 For Each cl In clm.Cells 20 txt = cl.Shape.TextFrame2.TextRange.Text 21 Call 作業部分(txt, cl.Shape) 22 Next cl 23 Next clm 24 End If 25 26 Next shp 27 Next sld 28End Sub 29 30 31Private Sub 作業部分(txt As String, shp As Object) 32 Dim RepList As Variant 33 RepList = Array("●", "●", "●") 34 35 Dim pos As Long 36 Dim Strnum As Long 37 Dim i As Long 38 For i = 0 To 2 '★ 39 Strnum = 1 40 While InStr(Strnum, txt, RepList(i), vbBinaryCompare) > 0 41 pos = InStr(Strnum, txt, RepList(i), vbBinaryCompare) 42 shp.TextFrame2.TextRange.Characters(pos + 1).Font.Subscript = msoTrue 43 Strnum = Strnum + 2 44 Wend 45 Next i '★★ 46End Sub

投稿2019/12/28 12:45

hatena19

総合スコア33699

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hSpringsteen

2019/12/28 13:15

ありがとうございます。上記回答の引数にsldも加えたところ、無事に成功いたしました。 初めてまともに呼び出しプロシージャを使用しましたが、引数の使い方について要諦を理解できた気がします。 この経験を軸に勉強していきたいです。  作業時間自体は伸びて重くなった気がするのが気になりますが、これから検証していこうと思います。 変数宣言についてのご指摘も勉強になります。ありがとうございました。
mike2mike4

2019/12/28 14:11

解決したのでしたら、「解決済み」にしてくださいな。お願いします。
hSpringsteen

2019/12/29 03:41

送信エラーが起きていました。ベストアンサーをつけました。すみません
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問