文字列の中の必要な部分にだけ書式設定をする

指定した文字の書式だけを変更する

記入見本作り

記入例を作りたかったんだが、日付の欄は、

f:id:akashi_keirin:20170507184321j:plain

こんな感じで、「月」と「日」と「(」、「)」をあらかじめ入れておいて、月・日・曜日だけを書いてもらうようにしている。

んで、記入者に書いてもらう部分だけを手書き風のフォントに変えて記入例を作ろうと思った。

しかし、ちょっと考えたら分かると思うが、これはめんどくさい。

たとえば、
7月23日(日)
という記入例を作ろうと思ったら、
「7」と「23」と「日」(曜日の方)だけを選択してフォントを変える
というしちめんどくさいことになる。

まあ、ちまちまと時間をかけて努力するのが好きな人ならそれほど苦痛ではないだろうが、私にとっては端的に苦痛ですw

んで、WordVBAの練習も兼ねてやってみた。

必要な部分だけ書式を変更するマクロ

Wordのオブジェクト構造がイマイチよく分かっとらんので、かなり行き当たりばったりのコードだと思うが、恥ずかしげもなく載せる。

リスト1
Option Explicit
Public Const FONT_TO_USE As String = "HG正楷書体-PRO"    '……(1)'
Public Sub setFontNameAndItalic()
  Dim chr As String    '……(2)'
  Dim i As Integer
  Dim numOfChar As Integer
	Dim flg As Boolean
  numOfChar = Selection.Range.Characters.Count    '……(3)'
  For i = 1 To numOfChar
    chr = Selection.Range.Characters(i)    '……(4)'
    If flg = True And chr <> ")" Then    '……(5)'
      With Selection.Range.Characters(i).Font    '……(*)'
        .Name = FONT_TO_USE
        .Italic = True
      End With
    End If
    If chr = "月" Or chr = "日" Or _
       chr = "(" Or chr = ")" Then    '……(6)'
      If chr = "(" Then flg = True    '……(7)'
      If chr = ")" Then flg = False    '……(8)'
    Else
      With Selection.Range.Characters(i).Font
        .Name = FONT_TO_USE
        .Italic = True
      End With
    End If
  Next
End Sub

改めて見直すと、ブサイクなコードです。。。(´・ω・`)ショボーン

まずは、(*)のところ。実はこれがメインの処理だったりする。

With Selection.Range.Characters(i).Font    '……(*)'
  .Name = FONT_TO_USE
  .Italic = True
End With

まず、Withでまとめている

Selection.Range.Characters(i).Font

では、選択箇所のRangeオブジェクトの中にある文字列Charactersコレクションのi番目の文字のFontプロパティを呼び出して、Fontオブジェクトを取得している。

んでもって、次の2行、

.Name = FONT_TO_USE
.Italic = True

でフォントの種類と斜体を設定する。

この処理を、それぞれの文字に対して実行するかどうかを切り替える、というやり方をしている。

ちなみに、「FONT_TO_USE」というのは定数で、リスト1の(1)で

Public Const FONT_TO_USE As String = "HG正楷書体-PRO"

と指定している。

(2)からの4行は、変数の宣言。

chr

Charactersコレクションから取得した1文字を入れる。(*)の処理を施すかどうかの条件判定に使用。別になくても良いが、コードを短くするために使っている。

i

おなじみループカウンタ。

numOfChar

選択中の文字数を格納する。Forループの上限値として使用。

flg

(*)の処理を行うかどうかを切り替えるためのフラグ。

(3)の

numOfChar = Selection.Range.Characters.Count

では、CharactersコレクションのCountプロパティを用いて文字数を取得し、変数numOfCharに格納。

ここからがForループの中身。

まず、(4)の

chr = Selection.Range.Characters(i)

で1文字を変数chrに格納。

(5)の

If flg = True And chr <> ")" Then

という条件分岐により、この段階でflgがTrueになっていたら、「)」でない限り(*)の処理を実行してしまう。

(7)のところで、「(」に出会ったらflgをTrueにするようにしているので、「(」に出会った直後のループでは、(*)を実行する。ただし、その直後はflgがTrueのままなので、放っておいたら「)」にまで(*)を実行してしまう。

それを防ぐための条件設定。うーーーむ、ブサイクすぎる。。。

(6)の

If chr = "月" Or chr = "日" Or chr = "(" Or chr = ")" Then

は、一番初歩的な条件設定。

「月」、「日」、「(」、「)」だったら何もしない、ということ。

ただし、めんどくさいのは、(*)の処理を施したい対象の中にも「月」、「日」という文字があること。言うまでもなく曜日を表す方の「月」、「日」だ。

幸い、曜日を表す方の「月」、「日」には、
「()」で括られている
という特徴があるので、
「(」に出会ったらスイッチオン、「)」に出会ったらスイッチオフ
というやり方にした。

……と書いているうちに、
カッコで括られているのは1文字って決まってるんだから、「(」に出会って次の1字に(*)の処理を施したら即flgをFalseにしたらいいんじゃね???
と思いついたというのは内緒だw

(7)、(8)の

If chr = "(" Then flg = True
If chr = ")" Then flg = False

がスイッチ切り替え。

「(」に出会ったらスイッチオン、「)」に出会ったらスイッチオフ、というイメージ。

実行結果

f:id:akashi_keirin:20170507184325j:plain

こんなふうに、日付欄を選択して実行すると、

f:id:akashi_keirin:20170507184330j:plain

この通り、意図したとおりの結果となった。

おわりに

ツッコミどころ満載のコードだということは認めます。

正直、Wordのオブジェクト構造がイマイチ理解できていないので、アホみたいなコードになっていると思います。これを機に勉強しようとは思うものの、ホントにやるかどうかは分かりませんw

ただ、ちょい書きでこのぐらいできたら、しちめんどくさい作業をせずに済む(しかも、コードを書くのは楽しいので、しょうもないはずの作業が楽しくなる)ので、まあええかな、と。

@akashi_keirin on Twitter