3

私は約持っています。RTF を含む Excel の 12000 セル (書式タグを含む)。フォーマットされていないテキストに到達するには、それらを解析する必要があります。

これは、テキストを含むセルの 1 つの例です。

{\rtf1\ansi\deflang1060\ftnbj\uc1
{\fonttbl{\f0 \froman \fcharset0 Times New Roman;}{\f1 \fswiss \fcharset238
Arial;}}
{\colortbl ;\red255\green255\blue255 ;\red0\green0\blue0 ;}
{\stylesheet{\fs24\cf2\cb1 Normal;}{\cs1\cf2\cb1 Default Paragraph Font;}}
\paperw11908\paperh16833\margl1800\margr1800\margt1440\margb1440\headery720\footery720
\deftab720\formshade\aendnotes\aftnnrlc\pgbrdrhead\pgbrdrfoot
\sectd\pgwsxn11908\pghsxn16833\marglsxn1800\margrsxn1800\margtsxn1440\margbsxn1440
\headery720\footery720\sbkpage\pgncont\pgndec
\plain\plain\f1\fs24\pard TPR 0160 000\par IPR 0160 000\par OB-R-02-28\par}

そして、私が本当に必要なのはこれだけです:

TPR 0160 000
IPR 0160 000
OB-R-02-28

セルを単純にループして不要なフォーマットを削除することの問題は、これらの 12000 個のセルのすべてがこれほど単純ではないということです。したがって、多くの異なるバージョンを手動で検査し、いくつかのバリエーションを作成する必要があります。それでも最終的には多くの手作業が必要になります。

しかし、1 つのセルの内容を空のテキスト ドキュメントにコピーして RTF として保存し、MS Word で開くと、テキストが即座に解析され、必要なものが正確に得られます。残念ながら、12000 個のセルに対してこれを行うのは非常に不便です。

そこで、セルの内容をWordに移動し、強制的に解析してから、結果を元のセルにコピーするVBAマクロについて考えていました。残念ながら、私はそれを行う方法がよくわかりません。

誰にもアイデアはありますか?それとも別のアプローチですか?解決策や正しい方向へのプッシュに本当に感謝しています.

TNX!

4

4 に答える 4

7

Word を使用してテキストを解析したい場合は、この関数が役に立ちます。コメントが示すように、MS Word Object Library への参照が必要です。

Function ParseRTF(strRTF As String) As String
Dim wdDoc As Word.Document 'Ref: Microsoft Word 11.0 Object Library'
Dim f     As Integer       'Variable to store the file I/O number'

'File path for a temporary .rtf file'
Const strFileTemp = "C:\TempFile_ParseRTF.rtf"

'Obtain the next valid file I/O number'
f = FreeFile

'Open the temp file and save the RTF string in it'
Open strFileTemp For Output As #f
    Print #f, strRTF
Close #f

'Open the .rtf file as a Word.Document'
Set wdDoc = GetObject(strFileTemp)

'Read the now parsed text from the Word.Document'
ParseRTF = wdDoc.Range.Text

'Delete the temporary .rtf file'
Kill strFileTemp

'Close the Word connection'
wdDoc.Close False
Set wdDoc = Nothing
End Function

次のようなものを使用して、12,000 個のセルごとに呼び出すことができます。

Sub ParseAllRange()
Dim rngCell As Range
Dim strRTF  As String

For Each rngCell In Range("A1:A12000")

    'Parse the cell contents'
    strRTF = ParseRTF(CStr(rngCell))

    'Output to the cell one column over'
    rngCell.Offset(0, 1) = strRTF
Next
End Sub

ParseRTF 関数の実行には約 1 秒かかります (少なくとも私のマシンでは)。したがって、12,000 セルの場合、約 3 時間半かかります。


週末にこの問題について考えてみたところ、これにはより良い (より迅速な) 解決策があると確信していました。

クリップボードの RTF 機能を思い出し、RTF データをクリップボードにコピーし、Word doc に貼り付け、結果のプレーン テキストを出力するクラスを作成できることに気付きました。このソリューションの利点は、rtf 文字列ごとにワード doc オブジェクトを開いたり閉じたりする必要がないことです。ループの前に開き、ループの後に閉じることができます。

以下は、これを実現するためのコードです。これは、clsRTFParser という名前のクラス モジュールです。

Private Declare Function GlobalAlloc Lib "kernel32" _
                (ByVal wFlags&, ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" _
                (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" _
                (ByVal hMem As Long) As Long
Private Declare Function lstrcpy Lib "kernel32" _
                (ByVal lpString1 As Any, ByVal lpString2 As Any) As Long

Private Declare Function OpenClipboard Lib "user32" _
                (ByVal Hwnd As Long) As Long
Private Declare Function EmptyClipboard Lib "user32" () As Long
Private Declare Function RegisterClipboardFormat Lib "user32" Alias _
                "RegisterClipboardFormatA" (ByVal lpString As String) As Long
Private Declare Function SetClipboardData Lib "user32" _
                (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function CloseClipboard Lib "user32" () As Long

'---'

Dim wdDoc As Word.Document 'Ref: Microsoft Word 11.0 Object Library'

Private Sub Class_Initialize()
Set wdDoc = New Word.Document
End Sub

Private Sub Class_Terminate()
wdDoc.Close False
Set wdDoc = Nothing
End Sub

'---'

Private Function CopyRTF(strCopyString As String) As Boolean
Dim hGlobalMemory  As Long
Dim lpGlobalMemory As Long
Dim hClipMemory    As Long
Dim lngFormatRTF   As Long

'Allocate and copy string to memory'
hGlobalMemory = GlobalAlloc(&H42, Len(strCopyString) + 1)
lpGlobalMemory = GlobalLock(hGlobalMemory)
lpGlobalMemory = lstrcpy(lpGlobalMemory, strCopyString)

'Unlock the memory and then copy to the clipboard'
If GlobalUnlock(hGlobalMemory) = 0 Then
    If OpenClipboard(0&) <> 0 Then
        Call EmptyClipboard

        'Save the data as Rich Text Format'
        lngFormatRTF = RegisterClipboardFormat("Rich Text Format")
        hClipMemory = SetClipboardData(lngFormatRTF, hGlobalMemory)

        CopyRTF = CBool(CloseClipboard)
    End If
End If
End Function

'---'

Private Function PasteRTF() As String
Dim strOutput As String

'Paste the clipboard data to the wdDoc and read the plain text result'
wdDoc.Range.Paste
strOutput = wdDoc.Range.Text

'Get rid of the new lines at the beginning and end of the document'
strOutput = Left(strOutput, Len(strOutput) - 2)
strOutput = Right(strOutput, Len(strOutput) - 2)

PasteRTF = strOutput
End Function

'---'

Public Function ParseRTF(strRTF As String) As String
If CopyRTF(strRTF) Then
    ParseRTF = PasteRTF
Else
    ParseRTF = "Error in copying to clipboard"
End If
End Function

次のようなものを使用して、12,000 個のセルごとに呼び出すことができます。

Sub CopyParseAllRange()
Dim rngCell As Range
Dim strRTF  As String

'Create new instance of clsRTFParser'
Dim RTFParser As clsRTFParser
Set RTFParser = New clsRTFParser

For Each rngCell In Range("A1:A12000")

    'Parse the cell contents'
    strRTF = RTFParser.ParseRTF(CStr(rngCell))

    'Output to the cell one column over'
    rngCell.Offset(0, 1) = strRTF
Next
End Sub

私のマシンでRTF文字列の例を使用してこれをシミュレートしました。12,000 個のセルの場合、2 分半かかりました。これははるかに合理的な時間枠です。

于 2009-11-17T10:22:18.743 に答える
1

ここでのソリューションの一部では、MS Word Object Library への参照が必要です。配られたカードで遊んでみると、それに頼らない解決策を見つけました。RTF タグや、フォント テーブルやスタイルシートなどの他の綿毛をすべて VBA で取り除きます。お役に立てるかもしれません。私はあなたのデータに対してそれを実行しましたが、空白を除いて、あなたが期待したものと同じ出力が得られました.

これがコードです。

まず、文字列が英数字かどうかを確認します。1 文字の長さの文字列を指定します。この関数は、あちこちで区切りを設定するために使用されます。

Public Function Alphanumeric(Character As String) As Boolean
   If InStr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-", Character) Then
       Alphanumeric = True
   Else
       Alphanumeric = False
   End If
End Function

次は、グループ全体を削除します。これを使用して、フォント テーブルやその他のごみを取り除きます。

Public Function RemoveGroup(RTFString As String, GroupName As String) As String
    Dim I As Integer
    Dim J As Integer
    Dim Count As Integer

    I = InStr(RTFString, "{\" & GroupName)

    ' If the group was not found in the RTF string, then just return that string unchanged.
    If I = 0 Then
        RemoveGroup = RTFString
        Exit Function
    End If

    ' Otherwise, we will need to scan along, from the start of the group, until we find the end of the group.
    ' The group is delimited by { and }. Groups may be nested, so we need to count up if we encounter { and
    ' down if we encounter }. When that count reaches zero, then the end of the group has been found.
    J = I
    Do
        If Mid(RTFString, J, 1) = "{" Then Count = Count + 1
        If Mid(RTFString, J, 1) = "}" Then Count = Count - 1
        J = J + 1
    Loop While Count > 0

    RemoveGroup = Replace(RTFString, Mid(RTFString, I, J - I), "")

End Function

さて、この関数はすべてのタグを削除します。

Public Function RemoveTags(RTFString As String) As String
    Dim L As Long
    Dim R As Long
    L = 1
    ' Search to the end of the string.
    While L < Len(RTFString)
        ' Append anything that's not a tag to the return value.
        While Mid(RTFString, L, 1) <> "\" And L < Len(RTFString)
            RemoveTags = RemoveTags & Mid(RTFString, L, 1)
            L = L + 1
        Wend
    
        'Search to the end of the tag.
        R = L + 1
        While Alphanumeric(Mid(RTFString, R, 1)) And R < Len(RTFString)
            R = R + 1
        Wend
        L = R
    Wend
End Function

明らかな方法で中括弧を削除できます。

Public Function RemoveBraces(RTFString As String) As String
    RemoveBraces = Replace(RTFString, "{", "")
    RemoveBraces = Replace(RemoveBraces, "}", "")
End Function

上記の関数をコピーしてモジュールに貼り付けたら、それらを使用して不要または不要なものを取り除く関数を作成できます。私の場合、以下は完全に機能します。

Public Function RemoveTheFluff(RTFString As String) As String
    RemoveTheFluff = Replace(RTFString, vbCrLf, "")
    RemoveTheFluff = RemoveGroup(RemoveTheFluff, "fonttbl")
    RemoveTheFluff = RemoveGroup(RemoveTheFluff, "colortbl")
    RemoveTheFluff = RemoveGroup(RemoveTheFluff, "stylesheet")
    RemoveTheFluff = RemoveTags(RemoveBraces(RemoveTheFluff))
End Function

これが役立つことを願っています。ワード プロセッサなどでは使用しませんが、データをスクレイピングする場合には役立つかもしれません。

于 2016-07-12T11:26:49.610 に答える