Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


2118 / 13645 ツリー ←次へ | 前へ→

【69827】書式を保持したまま置換したい めー 11/9/1(木) 17:57 質問[未読]
【69829】Re:書式を保持したまま置換したい UO3 11/9/2(金) 10:15 発言[未読]
【69831】Re:書式を保持したまま置換したい めー 11/9/2(金) 12:15 発言[未読]
【69833】Re:書式を保持したまま置換したい sasa 11/9/2(金) 13:09 回答[未読]
【69834】Re:書式を保持したまま置換したい めー 11/9/2(金) 13:27 発言[未読]
【69843】Re:書式を保持したまま置換したい n 11/9/2(金) 23:32 発言[未読]
【69847】Re:書式を保持したまま置換したい n 11/9/3(土) 12:31 発言[未読]
【69858】Re:書式を保持したまま置換したい めー 11/9/5(月) 18:19 お礼[未読]
【69849】Re:書式を保持したまま置換したい sasa 11/9/3(土) 16:50 回答[未読]
【69859】Re:書式を保持したまま置換したい めー 11/9/5(月) 18:24 お礼[未読]

【69827】書式を保持したまま置換したい
質問  めー  - 11/9/1(木) 17:57 -

引用なし
パスワード
   ブック内に含まれる全テキストボックスを対象に
文字の色やスタイル、サイズなどを変えることなく
文字を置換したいのですが、うまくいかず困っています。

例えば「このペンは赤ペンです」という文章がはいったテキストボックスで
「このペンは」は「MS Pゴシック」「黒色の文字」
「赤ペン」は「MS P明朝」「赤い文字」「太字」
「です」は「MS Pゴシック」「青色の文字」
というように、文字一つひとつに異なるフォントを設定しているとします。

このテキストボックス内の「赤ペン」の部分を「私の物」と変えたい場合に
「赤ペン」の部分の「MS P明朝」「赤い文字」「太字」を変えずに
文字だけ「私の物」に変えたいのです。

そこで、置換をする前に書式の情報を配列にいれてから、文字を置換し、
置換された文章に、元の書式を適用するようなコードを書いたのですが、
一部の書式は保持されるものの、すべての書式を保持することができませんでした。

下記がそのコードです。
解決方法や、参考になるようなサイトなどをご存知でしたら
ご教示の程お願い致します。

なお、下記のコードでは、「検索文字列」と「置換文字列」が
同じ文字数と想定して書いています。
「検索文字列」と「置換文字列」の文字数が違う場合のパターンは
コメントアウトで「検索と置換の文字数が違う場合」と記したところに
書く予定にしています。


Option Explicit
Option Base 1
Dim BeforeStr As String '      検索文字列
Dim AfterStr As String '      置換文字列
Dim bCount As Long '        検索文字列の文字数
Dim aCount As Long '        置換文字列の文字数
Dim dif As Long '          置換文字列の文字数−検索文字列の文字数
Dim WS As Worksheet '        ワークシート
Dim s As Shape '          オートシェイプ
Dim i As Long
Dim sCount As Long '        置換前・後のオートシェイプ内の文字数
Dim myName() As String '      フォントの種類
Dim myFontStyle() As String '    フォントのスタイル(太字、斜体など)
Dim mySize() As Variant '      フォントのサイズ
Dim myStrikethrough() As Boolean ' 水平な取り消し線の設定
Dim mySuperscript() As Variant '  上付き文字
Dim mySubscript() As Variant '   下付き文字
Dim myOutlineFont() As Boolean '  アウトライン フォント
Dim myShadow() As Boolean '     影付きフォント
Dim myUnderline() As Variant '   下線の種類
Dim myColorIndex() As Variant '   フォントの色
Dim bInStr As Long '        検索文字が何文字目からスタートするのか

Sub 文字列入力()
'  Application.ScreenUpdating = False
  BeforeStr = InputBox("置換前の文字列を入力してください。")
  AfterStr = InputBox("置換後の文字列を入力してください。")
  Call 文字列操作
End Sub

Sub 文字列操作()
  
  bCount = Len(BeforeStr) '      検索文字列の文字数
  aCount = Len(AfterStr) '      置換文字列の文字数
  dif = aCount - bCount '       検索文字列の文字数−置換文字列の文字数
  
  For Each WS In Worksheets '-----------------------------------------------▼For文 -(1)ブック内のシート全て
    WS.Activate
    
    For Each s In WS.Shapes '---------------------------------------------▼For文 -(2)シート内のテキストボックスすべて
      If s.Name Like "Text Box*" Then '---------------------------------▼If文  -(1)オートシェイプを判別
        s.Select
        sCount = Len(Selection.Characters.Text) '        置換前・後のオートシェイプ内の文字数
        bInStr = InStr(Selection.Characters.Text, BeforeStr) ' 検索文字が何文字目からスタートするのか

        Call 書式格納
        Call 置換
        Call 適用

      End If '---------------------------------------------------------▲If文  -(1)テキストボックスを判別
    Next '----------------------------------------------------------------▲For文 -(2)シート内のテキストボックスすべて
  Next '--------------------------------------------------------------------▲For文 -(1)ブック内のシート全て

'  Application.ScreenUpdating = True

End Sub

Sub 書式格納()
  ReDim myName(sCount) '      フォントの種類
  ReDim myFontStyle(sCount) '   フォントのスタイル(太字、斜体など)
  ReDim mySize(sCount) '      フォントのサイズ
  ReDim myStrikethrough(sCount) ' 水平な取り消し線の設定
  ReDim mySuperscript(sCount) '  上付き文字
  ReDim mySubscript(sCount) '   下付き文字
  ReDim myOutlineFont(sCount) '  アウトライン フォント
  ReDim myShadow(sCount) '     影付きフォント
  ReDim myUnderline(sCount) '   下線の種類
  ReDim myColorIndex(sCount) '   フォントの色
  
  For i = 1 To sCount '-----------------------------------------▼For文 -(3)オートシェイプ内の1文字〜最後の文字
    With Selection.Characters(Start:=i, Length:=i).Font '-----▼With  -(2)オートシェイプ内のフォント
      If IsNull(.Name) Then '-------------------------------▼IF文  -(2)フォントの種類のプロパティが空のとき
        myName(i) = "MS Pゴシック"
        Else
          myName(i) = .Name
      End If '----------------------------------------------▲IF文  -(2)フォントの種類のプロパティが空のとき
      If IsNull(.FontStyle) Then '--------------------------▲IF文  -(3)フォントのスタイルのプロパティが空のとき
        myFontStyle(i) = "標準"
        Else
          myFontStyle(i) = .FontStyle
      End If '----------------------------------------------IF文  -(3)フォントのスタイルのプロパティが空のとき
      mySize(i) = .Size
      myStrikethrough(i) = .Strikethrough
      mySuperscript(i) = .Superscript
      mySubscript(i) = .Subscript
      myOutlineFont(i) = .OutlineFont
      myShadow(i) = .Shadow
      myUnderline(i) = .Underline
      myColorIndex(i) = .ColorIndex
    End With '------------------------------------------------▲With  -(2)オートシェイプ内のフォント
  Next '--------------------------------------------------------▲For文 -(3)オートシェイプ内の1文字〜最後の文字
End Sub

Sub 置換()
  Selection.Characters.Text = Replace(Selection.Characters.Text, BeforeStr, AfterStr)
End Sub

Sub 適用()

  If aCount = bCount Then
  For i = 1 To sCount '-----------------------------------------▼For文 -(4)オートシェイプ内の1文字〜最後の文字
    With Selection.Characters(Start:=i, Length:=i).Font '-----▼With文 -(3)オートシェイプ内のフォント
        .Name = myName(i)
        .FontStyle = myFontStyle(i)
        .Size = mySize(i)
        .Strikethrough = myStrikethrough(i)
        .Superscript = mySuperscript(i)
        .Subscript = mySubscript(i)
        .OutlineFont = myOutlineFont(i)
        .Shadow = myShadow(i)
        .Underline = myUnderline(i)
        .ColorIndex = myColorIndex(i)
    
    End With '--------------------------------------------▲With文 -(3)オートシェイプ内のフォント
  Next '----------------------------------------------------▲For文 -(4)オートシェイプ内の1文字〜最後の文字
  End If
  
  sCount = Len(Selection.Characters.Text)
  ReDim Preserve myName(sCount) '      フォントの種類
  ReDim Preserve myFontStyle(sCount) '   フォントのスタイル(太字、斜体など)
  ReDim Preserve mySize(sCount) '      フォントのサイズ
  ReDim Preserve myStrikethrough(sCount) ' 水平な取り消し線の設定
  ReDim Preserve mySuperscript(sCount) '  上付き文字
  ReDim Preserve mySubscript(sCount) '   下付き文字
  ReDim Preserve myOutlineFont(sCount) '  アウトライン フォント
  ReDim Preserve myShadow(sCount) '     影付きフォント
  ReDim Preserve myUnderline(sCount) '   下線の種類
  ReDim Preserve myColorIndex(sCount) '   フォントの色
          
'▼ 検索と置換の文字数が違う場合******************** 

'▲ 検索と置換の文字数が違う場合******************** 

End Sub

【69829】Re:書式を保持したまま置換したい
発言  UO3  - 11/9/2(金) 10:15 -

引用なし
パスワード
   ▼めー さん:

おはようございます

まだ詳しく読んでいませんが、文字列内の文字ごとの書式処理は、
エクセルであればロジックも面倒ですし処理コストも大きくなるので
ワードあたりの【専門アプリ】で対応したほうがいいといったアドバイスをよく目にします。

それはさておき、たとえば

あいうえおかきくけこ この10文字が

あいう は 青
えおか は 赤
きくけこ は 黄色

こうだったとします。

で、 うえお を選んで こんにちは に変換しますと文字列としては

あいこんにちはかきくけこ になります。

ことのと、それぞれの文字は何色になる(何色にしたい)と考えておられますか?

【69831】Re:書式を保持したまま置換したい
発言  めー  - 11/9/2(金) 12:15 -

引用なし
パスワード
   UO3さん
ご回答ありがとうございます!

Excelでは難しそうですよね…。そもそも邪道な気がします。
ただ、ぜひとも実現させたいので、
今後もいろいろと無理なご質問をしてしまうと思いますが
ご教示いただけますと幸いです!

さて、

>あいうえおかきくけこ この10文字が

>あいう は 青
>えおか は 赤
>きくけこ は 黄色

>こうだったとします。

>で、 うえお を選んで こんにちは に変換しますと文字列としては

>あいこんにちはかきくけこ になります。

>ことのと、それぞれの文字は何色になる(何色にしたい)と考えておられますか?


上記の場合ですが、「こんにちは」の色は、
検索文字列「うえお」の最初の文字の色=「う」の色(この場合は「青」)にしたいと考えています。

当初「えお」に設定していた「赤」の色は消えてしまいますが

あい は 青
こんにちは も 青
か は 赤
きくけこ は 黄色

といったようにしたいと考えております。

まだコードには書き込んでおりませんが、
UO3さんさんの例のように、
検索文字列と置換文字列の文字数が異なる場合のために

(1)検索・置換文字が何文字目から何文字目なのかを割り出し
  (上記の場合は、3文字目〜7文字目)
(2)置換した文字列の前までは、もともとの書式をそのまま適用し
  (上記の場合は、1文字目〜2文字目の書式はそのまま)
(3)置換した文字列は、置換する前の文字列の最初の書式を適用し
  (上記の場合は、もともと「う」に設定されていた書式)
(4)置換した文字列以後は、検索文字列の書式をそのまま適用したい
  (上記の場合は、「か」以降はももともとの書式を適用)

といったことを実現するためのロジックを検討中です。

分かりづらい説明になってしまい、申し訳ありません。

引き続きアドバイスをお願いいたします。

【69833】Re:書式を保持したまま置換したい
回答  sasa  - 11/9/2(金) 13:09 -

引用なし
パスワード
   >例えば「このペンは赤ペンです」という文章がはいったテキストボックスで
>「このペンは」は「MS Pゴシック」「黒色の文字」
>「赤ペン」は「MS P明朝」「赤い文字」「太字」
>「です」は「MS Pゴシック」「青色の文字」
>というように、文字一つひとつに異なるフォントを設定しているとします。

示されたコードですが冗長すぎると思います。
書式を消すことなく置換すればいいでしょう。
あくまで一例です。詳細仕様はつめてください。

Sub CharacterInput()
 Dim BeforeStr$, AfterStr$
'  BeforeStr = InputBox("置換前の文字列を入力してください。")
'  AfterStr = InputBox("置換後の文字列を入力してください。")
  BeforeStr = "赤ペン": AfterStr = "私の物"
  If Len(AfterStr) = 0 Or Len(BeforeStr) = 0 Then Exit Sub
  CharacterSubstitution BeforeStr, AfterStr
End Sub

Sub CharacterSubstitution(ByVal BeforeStr$, ByVal AfterStr$)
 Dim ws, tb, bInStr&, dif&
 dif = Len(AfterStr) - Len(BeforeStr) 'ins
 For Each ws In Worksheets
  For Each tb In ws.TextBoxes
   bInStr = InStr(tb.Characters.Text, BeforeStr)
   If bInStr Then
    If dif > 0 Then tb.Characters(bInStr + 1, 1).Insert String(dif + 1, "*")
    If dif < 0 Then tb.Characters(bInStr + 1, Abs(dif)).Delete
    tb.Characters(bInStr, Len(AfterStr)).Text = AfterStr
   End If
  Next
 Next
End Sub

【69834】Re:書式を保持したまま置換したい
発言  めー  - 11/9/2(金) 13:27 -

引用なし
パスワード
       sasaさん

ご回答ありがとうございます!
たしかに長いとおもっていました…。
勉強になります。

さて、教えていただいた方法で早速ためしてみたのですが、
「私の物」の書式が「このペンは」はと同じ
「MS Pゴシック」「黒色の文字」になってしまいました。
「です」の書式は保持されました。

実は私の書いたコードも同様の現象が起こってしまい
ここに質問をした次第です。

原因は分からないのですが、PCの環境のせいかもしれないので
他のPCではどうなるか試し、この場で結果をご報告いたします。
(PCの環境は、WindowsXP Excel2003です)

【69843】Re:書式を保持したまま置換したい
発言  n  - 11/9/2(金) 23:32 -

引用なし
パスワード
   検索文字の2文字目以降を置換すると良いようです。
ただし、検索文字が1文字だけのケースがあると上手く行かないです。
そこを無理やり処理してますが、もっと良い方法があるのかも。

Sub test()
  Dim ws As Worksheet
  Dim tb As TextBox
  Dim chk As String
  Dim rep As String
  Dim n  As Long
  Dim p  As Long
  Dim x(8)
  
  chk = "うえお"
  rep = "こんにちは"
  n = Len(chk) - 1
  
  For Each ws In Worksheets
    For Each tb In ws.TextBoxes
      With tb
        Do
          p = InStr(.Text, chk)
          If p = 0 Then Exit Do
          If n > 0 Then
            .Characters(p + 1, n).Insert rep
            .Characters(p, 1).Delete
          Else
            With .Characters(p, 1).Font
              x(0) = .Name
              x(1) = .Size
              x(2) = .Bold
              x(3) = .Italic
              x(4) = .Shadow
              x(5) = .FontStyle
              x(6) = .ColorIndex
              x(7) = .OutlineFont
              x(8) = .Strikethrough
            End With
            .Characters(p, 1).Insert rep
            With .Characters(p, Len(rep)).Font
              .Name = x(0)
              .Size = x(1)
              .Bold = x(2)
              .Italic = x(3)
              .Shadow = x(4)
              .FontStyle = x(5)
              .ColorIndex = x(6)
              .OutlineFont = x(7)
              .Strikethrough = x(8)
            End With
          End If
        Loop
      End With
    Next
  Next
End Sub

また、Characters().Fontから下線などの情報がどうしても取れないみたいですね。
『Excel 2003 および Excel 2002 でオートシェイプに入力されている文字の正しいプロパティ情報が取得できない』
ht tp://support.microsoft.com/kb/959558/ja

1文字置換のケースでは、mhtファイル経由を検討してみてもいいかもしれません。

Sub sample()
  Const chk = "赤"
  Const rep = "黒"
  Dim ws As Worksheet
  Dim tmp As String
  Dim buf As String
  Dim n  As Long

  '作業用mhtファイル名を設定。 _
   同名既存ファイルがあれば上書きするので要注意。
  tmp = Application.DefaultFilePath & "\temp.mht"
  Set ws = ActiveSheet
  ActiveWorkbook.PublishObjects.Add( _
      xlSourceSheet, tmp, _
      ws.Name, "", _
      xlHtmlStatic).Publish True

  '作業用mhtファイルOpen。
  n = FreeFile
  Open tmp For Input As #n
  buf = StrConv(InputB(LOF(n), #n), vbUnicode)
  Close #n

  '---置換作業---
  buf = Replace$(buf, chk, rep)
  '--------------

  '作業ファイル書き込み直してOpen、Copy。
  n = FreeFile
  Open tmp For Output As #n
  Print #n, buf
  Close #n
  With Workbooks.Open(tmp)
    .Sheets(1).Copy ws
    .Close False
  End With
  '作業用mhtファイル削除。
  Kill tmp
  Set ws = Nothing
End Sub

【69847】Re:書式を保持したまま置換したい
発言  n  - 11/9/3(土) 12:31 -

引用なし
パスワード
   失礼..
置換内容によっては無限Loopでした...orz
※箇所の修正or追加必要です。

Sub test2()
  Dim ws As Worksheet
  Dim tb As TextBox
  Dim chk As String
  Dim rep As String
  Dim n  As Long
  Dim rn As Long '※
  Dim p  As Long
  Dim i  As Long '※
  Dim x(8)

  chk = "うえお"
  rep = "こんにちは"
  n = Len(chk) - 1
  rn = Len(rep) '※

  For Each ws In Worksheets
    For Each tb In ws.TextBoxes
      With tb
        i = 1
        Do
          p = InStr(i, .Text, chk) '※
          If p = 0 Then Exit Do
          If n > 0 Then
            .Characters(p + 1, n).Insert rep
            .Characters(p, 1).Delete
          Else
            With .Characters(p, 1).Font
              x(0) = .Name
              x(1) = .Size
              x(2) = .Bold
              x(3) = .Italic
              x(4) = .Shadow
              x(5) = .FontStyle
              x(6) = .ColorIndex
              x(7) = .OutlineFont
              x(8) = .Strikethrough
            End With
            .Characters(p, 1).Insert rep
            With .Characters(p, Len(rep)).Font
              .Name = x(0)
              .Size = x(1)
              .Bold = x(2)
              .Italic = x(3)
              .Shadow = x(4)
              .FontStyle = x(5)
              .ColorIndex = x(6)
              .OutlineFont = x(7)
              .Strikethrough = x(8)
            End With
          End If
          i = p + rn '※
        Loop
      End With
    Next
  Next
End Sub


2007以降なら楽なんですけどね。

chk = "うえお"
rep = "こんにちは"
n = Len(chk)
rn = Len(rep)
For Each ws In Worksheets
  For Each tb In ws.TextBoxes
    i = 1
    Do
      p = InStr(i, tb.Text, chk)
      If p = 0 Then Exit Do
      tb.Characters(p, n).Insert rep
      i = p + rn
    Loop
  Next
Next

【69849】Re:書式を保持したまま置換したい
回答  sasa  - 11/9/3(土) 16:50 -

引用なし
パスワード
   ▼めー さん:
>さて、教えていただいた方法で早速ためしてみたのですが、
>「私の物」の書式が「このペンは」はと同じ
>「MS Pゴシック」「黒色の文字」になってしまいました。
>「です」の書式は保持されました。
>(PCの環境は、WindowsXP Excel2003です)

先の一例マクロはWindowsVista&Excel2007 及び Windows7&Excel2010で動作確認し正常に動作しています。
Excel2003ではバグ(仕様)でうまくいかないと思われますが、
2003で全然ダメではなんなので、一応excel2000〜2010の環境で動くコードを示しておきます。(あくまで一応です?)

Sub CharacterSubstitution(ByVal sou$, ByVal des$)
 Dim ws As Worksheet, tb As TextBox, nn&, ll&
 ll = Len(sou)
 For Each ws In Worksheets
  For Each tb In ws.TextBoxes
   nn = InStr(tb.Characters.Text, sou)
   If nn Then
    If ll = 1 And nn <> Len(tb.Text) Then
     tb.Characters(nn + 2, 1).Insert tb.Characters(nn + 1, 2).Text
    End If
    tb.Characters(nn + 1, IIf(ll = 1, 1, ll - 1)).Text = des
    tb.Characters(nn, 1).Delete
   End If
  Next
 Next
End Sub

【69858】Re:書式を保持したまま置換したい
お礼  めー  - 11/9/5(月) 18:19 -

引用なし
パスワード
   nさん

ご回答ありがとうございます!
2003と2007では大きな隔たりがあるのですね…。

今回教えていただいた中ではじめて知ったことも多く
まだ分からないところもありますが、ひとつずつ理解しながら
詳細の仕様をつめていきたいと思います。

また、分からないところがありましたら教えていただけますと幸いです。

今後もよろしくお願いいたします!

【69859】Re:書式を保持したまま置換したい
お礼  めー  - 11/9/5(月) 18:24 -

引用なし
パスワード
   sasaさん

ご回答ありがとうございます!
バージョンによってコードの書き方を変えないといけないんですね。
いろいろな場面を想定して書くということを今後意識していきたいと思います。

まだ分からないところもありますが、ひとつずつ理解しながら
詳細の仕様をつめていきたいと思います。

また、分からないところがありましたら教えていただけますと幸いです。

今後もよろしくお願いいたします!

2118 / 13645 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free