将Excel中的RTF(富文本格式)代码转换为纯文本

4

我正在将一个数据库查询导出为Excel,但是获取到带有RTF格式的行。

这是Excel的屏幕截图

如何将这些字段转换为纯文本?我找到了一些相当旧的答案,所以想知道是否有新的方法。


https://dev59.com/FErSa4cB1Zd3GeqPTyFR - Slai
@Slai 那是我读过的第一篇文章。它很老了。我尝试过,但它不支持x64。我希望在过去的8年中有人找到了更好的方法。此外,我不擅长VBA。 - Ivan
3个回答

3

.Net Framework RichTextBox类可以执行转换。幸运的是,这个类已经设置了ComVisibleAttribute属性,所以可以在不太困难的情况下从VBA中使用。

我必须创建一个.tlb文件来引用。在

%SYSTEMROOT%\Microsoft.NET\Framework\currentver\

目录中,运行以下命令:

regasm /codebase system.windows.forms.dll

使用以下命令创建 system.windows.forms.tlb 文件。我已经在我的系统上有这个 .tlb 文件,但是我不得不重新创建它,以便能够在 VBA 中成功创建 .Net System.Windows.Forms RichTextBox 对象。

创建新的 .tlb 文件后,在 VBA 中通过工具->引用链接到您的项目中。

我在 Access 中编写了此测试代码,以演示解决方案。

Dim rtfSample As String
rtfSample = "{\rtf1\ansi\deflang1033\ftnbj\uc1 {\fonttbl{\f0 \froman \fcharset0 Times New Roman;}{\f1 \fswiss \fcharset0 Segoe UI;}} {\colortbl ;\red255\green255\blue255 ;} {\stylesheet{\fs22\cf0\cb1 Normal;}{\cs1\cf0\cb1 Default Paragraph Font;}} \paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\headery720\footery720\deftab720\formshade\aendnotes\aftnnrlc\pgbrdrhead\pgbrdrfoot \sectd\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\headery720\footery720\sbkpage\pgnstarts1\pgncont\pgndec \plain\plain\f1\fs22\lang1033\f1 hello question stem\plain\f1\fs22\par}"

Dim miracle As System_Windows_Forms.RichTextBox
Set miracle = New System_Windows_Forms.RichTextBox
With miracle
    .RTF = rtfSample 
    RTFExtractPlainText = .TEXT
End With

MsgBox RTFExtractPlainText(rtfSample)

根据结果

问题描述

我猜测在64位Windows和64位Office中,需要重新创建\Framework64\目录下的.tlb文件。我正在运行64位Win10和32位Office 2013,所以我需要一个32位的.tlb文件。


1

另一个选择是使用Microsoft Rich Textbox控件(但无法在x64 Office上测试)

Sub rtfToText()
    With CreateObject("RICHTEXT.RichtextCtrl") ' or add reference to Microsoft Rich Textbox Control for early binding and With New RichTextLib.RichTextBox
        .SelStart = 0                          ' needs to be selected
        .TextRTF = Join(Application.Transpose(Cells.CurrentRegion.Columns(1)))
        [C1] = .Text                           ' set the destination cell here

        ' or if you want them in separate cells:
        a = Split(.Text, vbNewLine)
        Range("C3").Resize(UBound(a) + 1) = Application.Transpose(a)
    End With
End Sub

谢谢您的回答。我一直在尝试运行它,但是我一直收到一个错误,说“ActiveX组件无法创建对象”。我已经允许了宏。 - Ivan
@Ivan,你能否在开发者选项卡中的插入菜单下的更多控件中添加Microsoft Rich Textbox Control到工作表中? - Slai
我无法在列表中找到该控件。 - Ivan
@Ivan 如果你找不到并注册这个控件,我建议使用更适合转换的东西,比如微软的Word,可以在32位模式下运行的脚本,或者更好的.NET应用程序。 - Slai

0

我重新审视这个问题,提供了两种JavaScript解决方案,而不是.NET

方法1

const parseRTF = require("rtf-parser");

let rtf = `{\\rtf1\\ansi\\deff0\\nouicompat{\\fonttbl{\\f0\\fnil\\fcharset0 Calibri;}{\\f1\\fnil\\fcharset204 Calibri;}{\\f2\\fnil Calibri;}}  {\\colortbl ;\\red0\\green0\\blue0;}  {\\*\\generator Riched20 10.0.19041}\\viewkind4\\uc1   \\pard\\cf1\\f0\\fs18\\lang1033 WEB1616 \\f1\\lang1071\\'ef\\'eb\\'e0\\'f2\\'e5\\'ed\\'ee \\'f1\\'ee \\'ea\\'e0\\'f0\\'f2\\'e8\\'f7\\'ea\\'e0\\par  \\'ca\\'f0\\'e8\\'f1\\'f2\\'e8\\'ed\\'e0 \\'c3\\'ee\\'eb\\'e0\\'e1\\'ee\\'f1\\'ea\\'e0 077640615\\par  \\'c2\\'e0\\'f0\\'f8\\'e0\\'e2\\'f1\\'ea\\'e0 6\\'e0\\par  1000 \\'d1\\'ea\\'ee\\'ef\\'bc\\'e5\\f2\\lang1033\\par  }  `;

function convertRTFtoPlainText(rtf) {
    return new Promise((resolve, reject) => {
        parseRTF.string(rtf, (err, doc) => {
            if (err) {
                reject(err);
            }

            let string = "";

            doc.content.forEach((item) => {
                if (item.content) {
                    item.content.forEach((span) => {
                        string += span.value;
                    });
                } else {
                    string += item.value;
                }
            });

            resolve(string.trim());
        });
    });
}

(async () => {
    let value = await convertRTFtoPlainText(rtf);

    console.log(value);
})();

方法二

const jsdom = require("jsdom");
const { JSDOM } = jsdom;

function stringToArrayBuffer(string) {
    if (string == null) return;
    let buffer = new ArrayBuffer(string.length);
    let bufferView = new Uint8Array(buffer);
    for (let i = 0; i < string.length; i++) {
        bufferView[i] = string.charCodeAt(i);
    }
    return buffer;
}

// callback = function to run after the DOM has rendered, defined when calling runRtfjs
function runRtfjs(rtf, callback, errorCallback) {
    const virtualConsole = new jsdom.VirtualConsole();
    virtualConsole.sendTo(console);

    let dom = new JSDOM(
        `
            <script src="./node_modules/rtf.js/dist/RTFJS.bundle.js"></script>

            <script>

                RTFJS.loggingEnabled(false);

                try {
                    const doc = new RTFJS.Document(rtfFile);

                    const meta = doc.metadata();
                    doc
                        .render()
                        .then(function(htmlElements) {

                            const div = document.createElement("div");
                            div.append(...htmlElements);

                            // window.done(meta, div.innerHTML);
                            // window.done(meta, div.innerText);
                            window.done(meta, div.textContent); // pass the data to the callback

                    }).catch(error => window.onerror(error))
                } catch (error){
                    window.onerror(error)
                }
            </script>
        `,
        {
            resources: "usable",
            runScripts: "dangerously",
            url: "file://" + __dirname + "/",
            virtualConsole,
            beforeParse(window) {
                window.rtfFile = stringToArrayBuffer(rtf);
                window.done = function (meta, html) {
                    callback(meta, html); // call the callback
                };
                window.onerror = function (error) {
                    errorCallback(error);
                };
            },
        }
    );
}

let rtf = `{\\rtf1\\ansi\\deff0\\nouicompat{\\fonttbl{\\f0\\fnil\\fcharset0 Calibri;}{\\f1\\fnil\\fcharset204 Calibri;}{\\f2\\fnil Calibri;}}  {\\colortbl ;\\red0\\green0\\blue0;}  {\\*\\generator Riched20 10.0.19041}\\viewkind4\\uc1   \\pard\\cf1\\f0\\fs18\\lang1033 WEB1616 \\f1\\lang1071\\'ef\\'eb\\'e0\\'f2\\'e5\\'ed\\'ee \\'f1\\'ee \\'ea\\'e0\\'f0\\'f2\\'e8\\'f7\\'ea\\'e0\\par  \\'ca\\'f0\\'e8\\'f1\\'f2\\'e8\\'ed\\'e0 \\'c3\\'ee\\'eb\\'e0\\'e1\\'ee\\'f1\\'ea\\'e0 077640615\\par  \\'c2\\'e0\\'f0\\'f8\\'e0\\'e2\\'f1\\'ea\\'e0 6\\'e0\\par  1000 \\'d1\\'ea\\'ee\\'ef\\'bc\\'e5\\f2\\lang1033\\par  }  `;

runRtfjs(
    rtf,
    (meta, html) => {
        console.log(html);
    },
    (error) => console.error(error)
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接