Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

RTF To Plain-Text

111 views
Skip to first unread message

Wolfgang Wolf

unread,
May 23, 2017, 4:04:27 AM5/23/17
to
Hallo,

hat jemand so was auf der Platte rumliegen? Der Weg über eine
unsichtbare RTF-Box ist mir zu langsam und selber parsen unsicher, zumal
mich zuerst tagelang in die Syntax einarbeiten müsste. Wisst ihr ob
Windows was dabei hat?

Schönen Gruß
W. Wolf

Dieter Strassner

unread,
May 23, 2017, 10:03:18 AM5/23/17
to
Hallo Wolfgang,

> hat jemand so was auf der Platte rumliegen? Der Weg über eine
> unsichtbare RTF-Box ist mir zu langsam und selber parsen unsicher, zumal
> mich zuerst tagelang in die Syntax einarbeiten müsste. Wisst ihr ob
> Windows was dabei hat?

also ob mein Vorschlag dazu wirklich schneller als das RTF-Control weiß
ich nicht:


Neues Projekt, WebBrowser-Control zuordnen und draufziehen und diesem
den Namen "wBC" geben

' Dieser Abschnitt wandelt RTF nach HTML oder Plaintext um:

Dim myRTF As String

'myRTF = Memo field with rtf encoded text in it

'Copy the contents of the Memo field with rtf to the clipboard
Dim lSuccess As Long
Dim lRTF As Long
Dim hGlobal As Long
Dim lpString As Long

lSuccess = OpenClipboard(0)
lRTF = RegisterClipboardFormat("Rich Text Format")
lSuccess = EmptyClipboard
hGlobal = GlobalAlloc(GMEM_MOVEABLE Or GMEM_DDESHARE, Len(myRTF))
lpString = GlobalLock(hGlobal)
CopyMemory lpString, ByVal myRTF, Len(myRTF)
GlobalUnlock hGlobal
SetClipboardData lRTF, hGlobal

CloseClipboard
GlobalFree hGlobal

Me.wBC.Object.Navigate "about:blank"
Do While Me.wBC.Object.ReadyState <> 4
DoEvents
Loop

Me.wBC.Object.Document.designMode = "On"

Do While Me.wBC.Object.ReadyState <> 4
DoEvents
Loop

Me.wBC.Object.Document.execCommand "Paste", False, True


strHTML = wBC.Object.Document.Body.innerhtml
strText = wBC.Object.Document.Body.innerText

' Quelle:
https://social.msdn.microsoft.com/Forums/office/en-US/141fb4cb-5dd8-4b01-bd83-8146a05cf54f/convert-rtf-format-to-html-format?forum=accessdev
' Author: Miroslav
' Stand: 29.05.2012


--
Viele Grüße - Dieter

EDV-Kommunikation Strassner e.K.
68623 Lampertheim
Internet: www.strassner.biz

Ulrich Möller

unread,
May 23, 2017, 2:08:41 PM5/23/17
to
Hallo Wolfgang,

Am 23.05.2017 um 10:04 schrieb Wolfgang Wolf:
> hat jemand so was auf der Platte rumliegen? Der Weg über eine
> unsichtbare RTF-Box ist mir zu langsam und selber parsen unsicher,
> zumal mich zuerst tagelang in die Syntax einarbeiten müsste. Wisst ihr
> ob Windows was dabei hat?

in einfachen Fällen ginge es auch mit einem regulärem Ausdruck (
Beispiele in Google)
oder aber vielleicht die ActiveX/Library aus diesem Projekt:
http://docfrac.net/wordpress/ ( neue Projektseite auf github:
https://github.com/teambob/docfrac)

Ulrich

Schmidt

unread,
May 23, 2017, 7:27:35 PM5/23/17
to
Am 23.05.2017 um 10:04 schrieb Wolfgang Wolf:

> hat jemand so was auf der Platte rumliegen? Der Weg über eine
> unsichtbare RTF-Box ist mir zu langsam und selber parsen unsicher, zumal
> mich zuerst tagelang in die Syntax einarbeiten müsste. Wisst ihr ob
> Windows was dabei hat?

Ausgehend von Dieters Routine...

Hier nochmal eine Abwandlung davon, die ohne Hilfs-Form
auskommt (in einer normalen Klasse implementiert,
vielleicht hilfreich in Services u.a.).

Anstelle von VBs Controls.Add usw. gibt es alternativ
auch das ATL-API:

Option Explicit 'cRtfConverter

Private Declare Function AtlAxWinInit Lib "atl" () As Long
Private Declare Function AtlAxGetControl Lib "atl" (ByVal hWnd As Long,
Unk As stdole.IUnknown) As Long
Private Declare Function CreateWindowExW Lib "user32" (ByVal dwExStyle
As Long, ByVal lpClassName As Long, ByVal lpWindowName As Long, ByVal
dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long,
ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long,
ByVal hInstance As Long, ByVal lpParam As Long) As Long
Private Declare Function DestroyWindow Lib "user32" (ByVal hWnd As Long)
As Long

Private hWndDoc As Long, Doc As Object, mHTML As String, mText As String

Private Sub Class_Initialize()
AtlAxWinInit
hWndDoc = CreateWindowExW(0, StrPtr("AtlAxWin"), StrPtr("mshtml:"),
0, 0, 0, 0, 0, 0, 0, 0, 0)
If hWndDoc Then AtlAxGetControl hWndDoc, Doc
If Not Doc Is Nothing Then Doc.DesignMode = "on"
End Sub

Public Sub Convert(sRtf As String)
Clipboard.Clear
Clipboard.SetText sRtf, vbCFRTF

Doc.execCommand "Paste", False, True
mHTML = Doc.body.innerHTML
mText = Doc.body.innerText
Doc.body.innerHTML = vbNullString 'reset for the next round
End Sub

Public Property Get HTML() As String
HTML = mHTML
End Property
Public Property Get Text() As String
Text = mText
End Property

Private Sub Class_Terminate()
Set Doc = Nothing
If hWndDoc Then DestroyWindow hWndDoc
End Sub

Testcode in eine Form:

Option Explicit

Const Rtf$ = "{\rtf1\ansi\deff0
{\colortbl;\red0\green0\blue0;\red255\green0\blue0;}" & _
"This line is the default color\line \cf2 This Line Is red}"

Private Converter As New cRtfConverter

Private Sub Form_Click()
Converter.Convert Rtf

Debug.Print Converter.HTML; vbLf
Debug.Print Converter.Text; vbLf
End Sub


Olaf

Wolfgang Wolf

unread,
May 24, 2017, 2:34:51 AM5/24/17
to
Danke Ulrich! Da hier neben Windows auch Linux angeboten wird, vermute
ich mal, dass hier nicht wie in -zig anderen Beispielen der Browser
verwendet wird. Könnte also interessant sein. Werde mich mal damit
beschäftigen.

Schönen Gruß
W. Wolf

Wolfgang Wolf

unread,
May 24, 2017, 2:56:16 AM5/24/17
to
Am 24.05.2017 um 01:27 schrieb Schmidt:
> Am 23.05.2017 um 10:04 schrieb Wolfgang Wolf:
>
>> hat jemand so was auf der Platte rumliegen? Der Weg über eine
>> unsichtbare RTF-Box ist mir zu langsam und selber parsen unsicher,
>> zumal mich zuerst tagelang in die Syntax einarbeiten müsste. Wisst ihr
>> ob Windows was dabei hat?
>
> Ausgehend von Dieters Routine...
>

Danke Olaf für den Code! Der Browser stört mich nicht, den verwende ich
eh in meinem Projekt. Dass zusätzlich das Clipboard-Objekt bemüht wird
ist blöd, weil damit eventuelle Zwischenablage-Daten überschrieben
werden. Grund genug, dass sich Anwender darüber aufregen (würde ich mich
auch).

Sollte Ulrichs Link untauglich sein, werde ich versuchen in deinem
Beispiel den Inhalt der Zwischenablage zu recyceln. Normale Werte wie
Zahlen, Texte und normales binäres Zeugs sollte damit machbar sein. Mal
sehen wie schnell/langsam das Ganze ist. Meine RTF-Daten kommen aus
einer DB und ich möchte damit ein Flex-Grid befüllen.

Habe hier noch weitere Beispiele, die die RTF-DLL aus den CommonControls
nutzen. Damit entfällt zumindest die OCX-Hülle des RTF-Controls. Ob das
geht, weiß ich noch nicht, weil die Beispiele letzten Endes auch ein UC
verwenden um die RTF-Box nachzubilden.

Schönen Gruß
W. Wolf

Dieter Strassner

unread,
May 24, 2017, 6:28:52 AM5/24/17
to
Hallo Wolfgang,

> Danke Olaf für den Code! Der Browser stört mich nicht, den verwende ich
> eh in meinem Projekt. Dass zusätzlich das Clipboard-Objekt bemüht wird
> ist blöd, weil damit eventuelle Zwischenablage-Daten überschrieben
> werden. Grund genug, dass sich Anwender darüber aufregen (würde ich mich
> auch).

wenn es schnell und ohne Zwischenablage gehen soll, wäre diese Lösung hier:

http://www.vb-helper.com/howto_rtf_to_html.html

http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=1545&lngWId=-10


evtl. eine Alternative.

Leider schon ein paar Jährchen alt und wohl nicht komplett zu Ende
programmiert. Habe mit der oberen Version einige RTF-Texte mit
unterschiedlichen Formatierung getestet, das lief erwartungsgemäß und
sehr flott. Mein Focus lage dabei auf der HTML-Ausgabe.

Für deinen Anwendungsfall müsstet Du alle nicht erwünschten
Formatierungen zur Ausgabe weglassen, dann bleibt Plaintext übrig.

Ist etwas Arbeit, aber sicherlich mit die (zur Laufzeit) schnellste Methode.

Wolfgang Wolf

unread,
May 24, 2017, 8:02:58 AM5/24/17
to
Am 24.05.2017 um 12:32 schrieb Dieter Strassner:
> Hallo Wolfgang,
[...]
> Ist etwas Arbeit, aber sicherlich mit die (zur Laufzeit) schnellste
> Methode.
>

Was bin ich froh, dass die entscheidenden Leute dieser NG treu geblieben
sind. Deine Links sind der perfekte Ansatz. Der Vatertag ist gerettet,
Danke!

Schönen Gruß
W. Wolf

Wolfgang Wolf

unread,
May 29, 2017, 9:01:00 AM5/29/17
to
Am 23.05.2017 um 20:08 schrieb Ulrich Möller:
Also, hier werden leider nur die Quellen angeboten, man müsste sich die
doxcom.dll selbst kompilieren. Überfordert momentan meine Werkzeugkiste.
Werde zuerst mal die anderen Möglichkeiten prüfen.

Schönen Gruß
W. Wolf

Wolfgang Wolf

unread,
May 29, 2017, 10:49:28 AM5/29/17
to
Am 24.05.2017 um 12:32 schrieb Dieter Strassner:
> Hallo Wolfgang,
>
> wenn es schnell und ohne Zwischenablage gehen soll, wäre diese Lösung hier:
>
> http://www.vb-helper.com/howto_rtf_to_html.html
>
> http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=1545&lngWId=-10
>
>
> evtl. eine Alternative.
>

Beide Beispiele verwenden den gleichen Code. Hier ein Auszug:
'seek first line with text on it
lBOS = InStr(strRTF, vbCrLf & "\deflang")
If lBOS = 0 Then GoTo finally Else lBOS = lBOS + 2

Meine RTF enthalten kein vbCrLf & "\deflang" und viele andere RTF-Files
auch nicht. Damit steigt die Proc aus noch bevor irgendwas konvertiert
wurde. Komisch, noch nicht mal in dem beiliegenden RTF-Beispiel ist
dieses vbCrLf & "\deflang" zu finden, was heißt, dass selbst die
Beispiele aus dem Projekt nicht funktionieren.

> Leider schon ein paar Jährchen alt und wohl nicht komplett zu Ende
> programmiert. Habe mit der oberen Version einige RTF-Texte mit
> unterschiedlichen Formatierung getestet, das lief erwartungsgemäß und
> sehr flott. Mein Focus lage dabei auf der HTML-Ausgabe.

Da musst du aber mit was anderem getestet haben, weil das hier
funktioniert endgültig nicht :-(

Schönen Gruß
W. Wolf

Dieter Strassner

unread,
May 30, 2017, 7:36:16 AM5/30/17
to
Hallo Wolfgang,


> Meine RTF enthalten kein vbCrLf & "\deflang" und viele andere RTF-Files
> auch nicht. Damit steigt die Proc aus noch bevor irgendwas konvertiert
> wurde. Komisch, noch nicht mal in dem beiliegenden RTF-Beispiel ist
> dieses vbCrLf & "\deflang" zu finden, was heißt, dass selbst die
> Beispiele aus dem Projekt nicht funktionieren.

den o.g. Stringkombination "vbCrLf & "\deflang" ist in meinen
RTF-Textbeispieln auch nicht enthalten (nur in Verbindung mit
Sprachnummern).


Aber wo ein Ziel ist, ist auch ein Weg....


strHTML = rtf2html3(rtfText) ' aus RTF-Text den HTML-Text holen

Dim H As MSHTML.HTMLDocument

Set H = New MSHTML.HTMLDocument
H.Body.innerHTML = strHTML
Text1.Text = H.Body.outerText ' ... Plaintext in Textbox ausgeben

Wolfgang Wolf

unread,
May 31, 2017, 1:49:25 AM5/31/17
to
Am 30.05.2017 um 13:40 schrieb Dieter Strassner:
Hi Dieter,

> Aber wo ein Ziel ist, ist auch ein Weg....
>
>
> strHTML = rtf2html3(rtfText) ' aus RTF-Text den HTML-Text holen
>

Verstehe das nicht! Wo kommt jetzt die Funktion rtf2html3 den her?
Meintest du die rtf2html aus deinen Links?

Genau das funktioniert ja leider nicht. Ich bekomme kein strHTML, weil
die Funktion gleich hinter InStr(strRTF, vbCrLf & "\deflang") verlassen
wird, Rückgabe = ""

Ok, ab hier machst du aus HTML Plain-Text. Aber dafür muss erst mal HTML
vorhanden sein. Und das liefert dieses rtf2html leider nicht.

> Dim H As MSHTML.HTMLDocument
>
> Set H = New MSHTML.HTMLDocument
> H.Body.innerHTML = strHTML
> Text1.Text = H.Body.outerText ' ... Plaintext in Textbox ausgeben
>

Habe mal diese Zeile mit "vbCrLf & "\deflang" raus genommen. Damit läuft
die Proc mehr schlecht als recht durch und liefert ein verhunztes HTML.
Das wäre mal ein Ansatz, macht aber sicher noch viel Arbeit und ich komm
nicht drumherum mich ganz tief in die RTF-Spec einzuarbeiten. Mach ich
ungern. Solche Standards sollte man einfach dazukaufen können. Hab aber
bisher nichts gefunden.

Schönen Gruß
W. Wolf

Wolfgang Wolf

unread,
May 31, 2017, 1:51:21 AM5/31/17
to
Am 29.05.2017 um 15:00 schrieb Wolfgang Wolf:

Hi Ulrich,
>
> Also, hier werden leider nur die Quellen angeboten, man müsste sich die
> doxcom.dll selbst kompilieren. Überfordert momentan meine Werkzeugkiste.
> Werde zuerst mal die anderen Möglichkeiten prüfen.
>

Mal vorsichtig gefragt: Hast du diese kompilierte DLL auf der Platte?
Wenn ja, könnte ich die haben?

Schönen Gruß
W. Wolf

Wolfgang Wolf

unread,
May 31, 2017, 3:38:52 AM5/31/17
to
Am 31.05.2017 um 08:30 schrieb Dieter Strassner:

>
> Viel Erfolg damit.
> Gruß
> Dieter
>

Hatte ich! Dieser Code funktioniert. Ist aber auch ein anderer als der
in den Links. Vielen Dank dafür.

Erste Tests: eine Zeile RTF <1ms, das ist gut!
Habe probehalber deinen schlanken Dreizeiler über MSHTML.HTMLDocument
mit angefügt, der braucht 30ms, aber auch nur wegen der Instanzierung
des HTML-Dokumentes. Ohne diese (die kann man ja auch einmalig global
machen) komme ich in der Summe auf ca. 1,5ms pro RTF-Zeile. Im
Vergleich, die RTF-Box braucht dafür doppelt so lang (bei bereits
geladenem Control).

Vermutlich kann ich durch den Umbau des Codes nach RTF2TXT noch mehr
raus holen. Auf deiner funktionierenden Basis sollte das nicht all zu
schwer sein.

Vielen Dank Dieter für diesen Code. War jetzt eine schwerere Geburt,
sorry, aber es hat sich echt gelohnt.

Schönen Gruß
W. Wolf

Dieter Strassner

unread,
May 31, 2017, 4:37:47 AM5/31/17
to
hallo Wolfgang,

sorry, das die Links nicht gepasst hatten, da habe ich mich irgendwie
vertan...


> Vermutlich kann ich durch den Umbau des Codes nach RTF2TXT noch mehr
> raus holen. Auf deiner funktionierenden Basis sollte das nicht all zu
> schwer sein.
>
> Vielen Dank Dieter für diesen Code. War jetzt eine schwerere Geburt,
> sorry, aber es hat sich echt gelohnt.

Falls du Mehrwert stiften möchtest:
Kannst ja dann mal deinen darus entstandenen schlanken RTF/Text-Parser
posten. :-)

Ulrich Möller

unread,
May 31, 2017, 4:48:58 AM5/31/17
to
Hallo Wolfgang,

Am 31.05.2017 um 07:51 schrieb Wolfgang Wolf:
>>
>> Also, hier werden leider nur die Quellen angeboten, man müsste sich die
>> doxcom.dll selbst kompilieren. Überfordert momentan meine Werkzeugkiste.
>> Werde zuerst mal die anderen Möglichkeiten prüfen.
>>
>
> Mal vorsichtig gefragt: Hast du diese kompilierte DLL auf der Platte?
> Wenn ja, könnte ich die haben?

Leider habe ich die kompilierte DLL nicht. Wenn ich mir den Sourcecode
anschaue, so ist das Code wohl für den BCC erstellt worden, den ich aber
vor langer Zeit schon entsorgt habe.
Auf der Sourceforge Seite unter
https://sourceforge.net/projects/docfrac/files/docfrac/3.1.1/ kannst du
aber die Version docfrac-win32-programming-3.1.1 herunterladen. Dort ist
die DLL/ActiveX und eine Testproject für VB enthalten. Ausprobiert habe
ich diese aber noch nicht.

Ulrich

Wolfgang Wolf

unread,
Jun 1, 2017, 1:33:08 AM6/1/17
to
Am 31.05.2017 um 10:49 schrieb Ulrich Möller:
> Hallo Wolfgang,
>
[...]
> die DLL/ActiveX und eine Testproject für VB enthalten. Ausprobiert habe
> ich diese aber noch nicht.
>
> Ulrich


Hallo Ulrich,

perfekt! Die Downloads in deine ersten Links hatten das alles nicht. Die
DLL ist relativ groß (728KB) weil sie zwei unterschiedliche Klassen
beinhaltet. Die Objektinstanzierung dauert aber auch nicht länger wie
beim HTML-Objekt. Die Konvertierung ist sogar noch ein bisschen
schneller wie der Code von Dieter. Das mag aber auch daran liegen, dass
die DLL nativ vorliegt, während der Dieter-Code noch in der IDE
ausgeführt wird.

Bin begeistert! Habe nun zwei gute Lösungen. Langfristig werde ich mich
doch noch in Dieters Code einarbeiten. Dann entfällt die externe
Abhängigkeit.

Also, vielen Dank noch mal für die Tipps und Links.

Schönen Gruß
W. Wolf

Ulrich Möller

unread,
Jun 1, 2017, 8:55:35 AM6/1/17
to
Hallo Wolfgang,

Am 01.06.2017 um 07:33 schrieb Wolfgang Wolf:
> perfekt! Die Downloads in deine ersten Links hatten das alles nicht.
> Die DLL ist relativ groß (728KB) weil sie zwei unterschiedliche
> Klassen beinhaltet. Die Objektinstanzierung dauert aber auch nicht
> länger wie beim HTML-Objekt. Die Konvertierung ist sogar noch ein
> bisschen schneller wie der Code von Dieter. Das mag aber auch daran
> liegen, dass die DLL nativ vorliegt, während der Dieter-Code noch in
> der IDE ausgeführt wird.
>
> Bin begeistert! Habe nun zwei gute Lösungen. Langfristig werde ich
> mich doch noch in Dieters Code einarbeiten. Dann entfällt die externe
> Abhängigkeit.
du hattest mal erwähnt, das die Daten aus einer DB stammen. Wenn das
nicht gerade RTF Textbausteine sind, sind die Formatierungen meist recht
einfach und dann sollte es auch einfach mit einem regulären Ausdruck
gehen. Die Replace Funktion arbeitet eigentlich sehr schnell.

Als Ansatz zum Test ein Link mit einem Beispiel, welches je nach
Anforderung auch noch vereinfacht werden könnte:
http://www.ozgrid.com/forum/showthread.php?t=170465 (am Ende auf der Seite).
Im Netz gibt es auch weitere Regex Ausdrücke, die das Problem angehen
und die auch oft in Verbindung mit DB-Feldern verwendet werden.

Ulrich




Wolfgang Wolf

unread,
Jun 2, 2017, 2:17:07 AM6/2/17
to
Am 01.06.2017 um 14:55 schrieb Ulrich Möller:
Hallo Ulrich
> du hattest mal erwähnt, das die Daten aus einer DB stammen. Wenn das
> nicht gerade RTF Textbausteine sind, sind die Formatierungen meist recht
> einfach und dann sollte es auch einfach mit einem regulären Ausdruck
> gehen. Die Replace Funktion arbeitet eigentlich sehr schnell.
>
> Als Ansatz zum Test ein Link mit einem Beispiel, welches je nach
> Anforderung auch noch vereinfacht werden könnte:
> http://www.ozgrid.com/forum/showthread.php?t=170465 (am Ende auf der
> Seite).
> Im Netz gibt es auch weitere Regex Ausdrücke, die das Problem angehen
> und die auch oft in Verbindung mit DB-Feldern verwendet werden.
>
> Ulrich
>

Hallo Ulrich,

Eigentlich hast du recht. Mein Bauch macht aber nicht mit. Zum einem
weiß ich nicht so recht ob ein regulärer Ausdruck alles abdeckt. Da
müsste ich viel testen.

Nächstes Problem ist die Abhängigkeit von VBScript. Das habe ich bisher
nicht in meinem Projekt. Und mal ehrlich, inzwischen vertraue ich einer
alten gedienten DLL eines Fremdanbieters, die ich regfree aus dem
Anwendungsverzeichnis instantiiere, mehr als den MS-Updates, die
gelegentlich was durcheinander bringen. Noch sicherer scheint mir der
eigene Code basierend auf Dieters Beispielen.

Werde aber deine Links behalten, so kurze Codeblöcke kann man leicht in
der eigenen Klasse unterbringen. Und nachdem hier VBScript lose gebunden
ist, entsteht auch keine Abhängigkeit, solange die Proc nicht aufgerufen
wird. Damit hätte ich eine zusätzliche Fallback-Lösung, wenn alles
andere versagt.

Das bringt mich auf eine weiter Idee: Ich verwende schon lange das
FlexGrid von ComponentOne in meinem Projekt. Hier ist eine
FlexString-Komponente dabei, die kann auch RegExpressions. Könnte ggf.
das auch mal testen.

Schönen Gruß
W. Wolf

0 new messages