[[20220104161958]] 『htmlを取得して、特定の要素を置換したい』(名無し) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『htmlを取得して、特定の要素を置換したい』(名無し)

タイトルの内容を詳しく説明すると、vbaでhtmlを取得して、width='100'と書かれている箇所をwidth='100px'というように数字の後ろにpxを追加したいと考えています。
現在、htmlを取得して別シートに張り付けて、width='で検索して該当のセルに移動するところまではいけたのですが、数字の後ろにpxだけを入れることができない状況です。
流れといたしましては、別シートに張り付けてwidth='100px'の形にしたのちに再度htmlに置換した内容を上書きする形を想定しています。

考慮しないといけない点は、widt='100%'やpxがすでに入っているものに関してはそのままにすることです。

ご存じの方がいましたらご教授願います。


Sub mainTool()

    Dim wb As Workbook
    Dim ws, outputSheet As Worksheet
    Dim filePath, replaceWord As String

    Set wb = ActiveWorkbook
    Set ws = wb.ActiveSheet
    Set outputSheet = wb.Sheets(2)

        filePath = ws.Range("D4").Value

        inputFile (filePath)

        replaceWord = "width='"

        With outputSheet.Columns("A")
            .Replace what:=replaceWord, replacement:=""
        End With

        MsgBox "終了しました"

End Sub

Function inputFile(filePath)

    Dim wb As Workbook
    Dim outputSheet As Worksheet
    Dim buf As String, n As Long

    Set wb = ActiveWorkbook
    Set outputSheet = wb.Sheets(2)

    Open filePath For Input As #1
        Do Until EOF(1)
            Line Input #1, buf
            n = n + 1
            outputSheet.Cells(n, 1) = buf
        Loop
    Close #1

End Function

< 使用 Excel:Excel2016、使用 OS:Windows10 >


 width='100'をwidth='100px'に置き換えるだけでは、
 ダメなのでしょうか?
 Replace("width='100'", "width='100'", "width='100px'")

(tkit) 2022/01/04(火) 16:59


コメントありがとうございます。
widthは100だけではないので、すべての数字に対応しないといけないです・・・
最大で4桁です。
(名無し) 2022/01/04(火) 17:02

ちなみにセル内の値は以下のようなもので、width以外にも文字列があります。
<table id='tblHdr' width='980' border='0' cellspacing='0'>
(名無し) 2022/01/04(火) 17:13

 どこかに穴があるかもしれませんが、
 何となくそれらしい事ができたかもしれませんので投稿します。
 細かいことを聞かれても答えるスキルがありませんので、改良等はご自身でお願いします。

 Sub Sample()
    Debug.Print addpx("<table id='tblHdr' width='980' border='0' cellspacing='0'>")
    Debug.Print addpx("<table id='tblHdr' width='980%' border='0' cellspacing='0'>")
    Debug.Print addpx("<table id='tblHdr' width='980px' border='0' cellspacing='0'>")
 End Sub

 Function addpx(inp As String) As String
    Dim reg As Object
    Dim rm As Object
    Dim buf As String
    If Not InStr(inp, "width='") > 0 Then Exit Function
    Set reg = CreateObject("VBScript.RegExp")
    With reg
        .Global = True
        .ignorecase = True
        .Pattern = "width='\d{1,4}."
    End With
    Set rm = reg.Execute(inp)
    If Right(rm(0), 1) = "'" Then
        buf = Left(rm(0), Len(rm(0)) - 1) & "px'"
        addpx = Replace(inp, rm(0), buf)
    Else
        addpx = inp
    End If
 End Function
(寒) 2022/01/04(火) 18:24


 既に正規表現を使った回答がありますが、書いてしまったので投稿させていただく。

 パターンマッチを行う正規表現というのを使うと良いと思います。
 ・パターンにかっこを付けることで、それぞれのマッチ部分文字列が取得できます。
 (下記の$1,$2,$3がそれぞれの部分文字列を指します)
 ・そして、それらを置換後文字列に使うことができます。

 と言われても、正規表現を知らない方にはわからないかもしれません。
 参考程度に閲覧ください。
 どなたか別の方の回答をお待ちください。

 下記のコードはstr1をstr2に置換するプリミティブな例です。
 HTMLテキストをstr1に見立てれば、同様にできるはずです。

 Sub test()
     Dim reg As Object
     Set reg = CreateObject("VBScript.RegExp")

     '正規表現の指定
     With reg
         .Pattern = "(width=')(\d+)(')" 'パターンを指定
         .IgnoreCase = True       '大文字と小文字を区別するか(False)、しないか(True)
         .Global = True           '文字列全体を繰り返し検索するか(True)、しないか(False)
     End With

     Dim str1 As String, str2 As String
     str1 = "width='100', aaa,width='200', bbb"
     str2 = reg.Replace(str1, "$1$2px$3") '指定した正規表現を第2引数の区切り文字に置換
     Debug.Print str2  'width='100px', aaa,width='200px', bbb   と出力されます。
 End Sub 
(γ) 2022/01/04(火) 18:50

 HTMLでは px の単位は普通は指定しませんけど何か訳でもあるのですか。
(nm) 2022/01/04(火) 19:14

みなさま、コメントありがとうございます。

>寒さん、γさん
正規表現を使うことで特定の部分を置換することができるのですね。
実際にサンプルを動かしてみましたが、イメージ通りのものになりそうです。
これをもとに作成していきたいと思います。ありがとうございます。

>nmさん
IEからEdgeの移行でwidthやheightにpx指定をしないと効かなくなってしまったので、その対応をしないといけなくなったのでこのような置換プログラムを作成することになりました。

(名無し) 2022/01/05(水) 08:56


http://officetanaka.net/excel/vba/filesystemobject/textstream07.htm
にあるREADALLを使って、全体をbufに取り込んで、
これに対してre.Replaceを掛ければ、一挙に変換可能です。
それをまた、ファイルに書き込めば、ワークシートを経由せずに処理が済むと思われます。
老婆心ながら。
(γ) 2022/01/05(水) 09:29

 >widthやheightにpx指定をしないと効かなくなってしまったので
「効かなくなってしまった」とはどういうことですか。

 移行前の構文はどうなっているのでしょう。

(nm) 2022/01/05(水) 11:19


 > IEからEdgeの移行でwidthやheightにpx指定をしないと効かなくなってしまったので、

 もし、そんなことがあったら、世界中で大パニックになってます。
(hatena) 2022/01/05(水) 13:10

>Yさん
そのような方法があったのですね。
是非参考にしたいと思います。ありがとうございます。

>nmさん、hatenaさん
有識者に聞いたところ、意味のない作業になりそうです・・・
発見した人の発言力が強いため、間違いを指摘できなかったそうです。
なにか根拠があるのかどうかわからないのですが、ただ従っているだけの状況です・・・
(名無し) 2022/01/05(水) 14:44


下記プログラムでstr2までデバッグを行い、str2には置換されている値が入っていることを確認したのですが、.writeメソッドでエラーが出て書き込みができない原因がわかりません。
textstreamクラスを調べたのですが、With fso.GetFile(filePath).OpenAsTextStreamで.Writeが使えるという認識なのですが間違っているのでしょうか。
ご教授願います。


Sub mainTool()

    Dim wb As Workbook
    Dim ws, outputSheet As Worksheet
    Dim filePath, replaceWord As String
    Dim rng, searchRng As Range
    Dim firstAddress As String

    Set wb = ActiveWorkbook
    Set ws = wb.ActiveSheet
    Set outputSheet = wb.Sheets(2)

        filePath = ws.Range("D4").Value

        Dim fso As Object, buf As String
        Set fso = CreateObject("Scripting.FileSystemObject")
        'C:\Work\Sample.txtの全ての文字を読み込んで表示します
        With fso.GetFile(filePath).OpenAsTextStream
            buf = .Readall
            MsgBox buf

                Dim reg As Object
                Set reg = CreateObject("VBScript.RegExp")
                '正規表現の指定
                With reg
                    .Pattern = "(width=')(\d+)(')" 'パターンを指定
                    .IgnoreCase = True       '大文字と小文字を区別するか(False)、しないか(True)
                    .Global = True           '文字列全体を繰り返し検索するか(True)、しないか(False)
                End With

                Dim str1 As String, str2 As String
                    str1 = buf
                    MsgBox buf
                    str2 = reg.Replace(str1, "$1$2px$3")

            .Write (str2)

        End With
        Set fso = Nothing

End Sub
(名無し) 2022/01/06(木) 10:05


https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/openastextstream-method
 を参照してください。

VBAのオブジェクトブラウザで見ると

 Function OpenTextFile(FileName As String, [IOMode As IOMode = ForReading], [Create As Boolean = False], [Format As Tristate = TristateFalse]) As TextStream

となっているので、IOMode の既定値は ForReading です

読み込みと書き込みを同時にできるモードはないので、
いったん閉じてから、再度 IOMode を ForWriting で開き直すか
別のファイルに書き込むようにしてください。
(とおりすがり) 2022/01/06(木) 10:19


 気のすすまない処理のようですが、一応コメントしておきます。

 (1)元のファイルは残しておいて、修正済みのフォルダに別途保存するのがよいでしょう。
 空のファイルで上書きしてしまうなどということが起きないとも限らないし、
 よほど自信があれば別だが、元に戻せる余地は残すのが安全でしょう。
 どうしても上書きというなら、結果が確認できてから、手作業でまとめて上書きすればよい。

 (2)また、パターンの話ですが、
 ・$1と$2は区別する必要は本来なかったですね。まあ分かりやすいかとは思ったわけですが。
 ・'100' のほかに "100" と書く流儀もあるでしょう。それは組み込んでおきました。
 ・このほか、途中に半角スペースが入るかもしれないので、
   その冗長性も考えたほうがいいかもしれない。(まあ、形式的にやったことにするなら不要だが)
 ・CSSで幅指定することのほうがむしろ多いのではないかと想像します。
  (まあ、徒に仕事を増やすので歓迎はされない指摘だが)

 既にご指摘があったとおりです。
 念のため、参考コードを挙げておきます。色々な書き方があります。一例です。

 Sub mainTool()
     Dim fso As Object
     Dim reg As Object
     Dim folder1 As String
     Dim folder2 As String
     Dim fname As String
     Dim buf As String
     Dim str2 As String

     Set fso = CreateObject("Scripting.FileSystemObject")

     Set reg = CreateObject("VBScript.RegExp")
     '正規表現の設定
     With reg
         .Pattern = "(width=['""]\d+)(['""])"    'パターンを指定
         .IgnoreCase = True       '大文字と小文字を区別しない
         .Global = True           '文字列全体を繰り返し検索
     End With

     folder1 = "D:\mydocuments\202201\test\" '■適宜修正下さい
     folder2 = folder1 & "modified\"         '■適宜修正下さい

     fname = Dir(folder1 & "*.txt")          'htm(l) であれば "*.htm" とします。

     Do While fname <> ""
         'ファイル読み込み
         With fso.GetFile(folder1 & fname).OpenAsTextStream
             buf = .Readall
             .Close
         End With
         '置換
         str2 = reg.Replace(buf, "$1px$2")
         'ファイル書き込み
         With fso.CreateTextFile(folder2 & fname, True)'最後のTrueは強制上書き
             .Write str2
             .Close
         End With
         fname = Dir()   '次のファイルのファイル名を取得
     Loop
 End Sub
(γ) 2022/01/06(木) 12:30

>とおりすがりさん、γさん
ありがとうございます。
サンブルコードまで丁寧に記載していただいて、大変助かりました。
無事、想定していたものが作成することができました。
(名無し) 2022/01/06(木) 17:21

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.