如何在C#中剥离RTF标签提取内嵌的HTML内容?
从内嵌HTML的RTF字符串中提取完整HTML的C#实现
我有一段内嵌HTML格式的RTF字符串(如下所示),需要用C#代码剥离RTF标签,提取出完整的HTML内容。之前尝试过提取纯文本的方案,但没能得到理想结果,求可行的实现方法。
{\rtf1\ansi\ansicpg1252\fromhtml1 \fbidis \deff0{\fonttbl {\f0\fswiss Arial;} {\f1\fmodern Courier New;} {\f2\fnil\fcharset2 Symbol;} {\f3\fmodern\fcharset0 Courier New;}} {\colortbl\red0\green0\blue0;\red0\green0\blue255;} \uc1\pard\plain\deftab360 \f0\fs24 {\*\htmltag19 <html>} {\*\htmltag34 <head>} {\*\htmltag1 \par } {\*\htmltag1 \par } {\*\htmltag41 </head>} {\*\htmltag2 \par } {\*\htmltag50 <body>} {\*\htmltag0 \par } {\*\htmltag96 <div>}\htmlrtf {\htmlrtf0 {\*\htmltag112 <br>}\htmlrtf \par \htmlrtf0 {\*\htmltag0 \par } {\*\htmltag112 <br>}\htmlrtf \par \htmlrtf0 {\*\htmltag0 \par } {\*\htmltag112 <br>}\htmlrtf \par \htmlrtf0 {\*\htmltag0 \par } {\*\htmltag96 <div style="width:100%;height:20px;">}\htmlrtf {\htmlrtf0 {\*\htmltag64}\htmlrtf {\htmlrtf0 {\*\htmltag148 <span style="white-space:nowrap;color:#5F5F5F;opacity:.36;">}\htmlrtf {\htmlrtf0 ________________________________________________________________________________ {\*\htmltag156 </span>}\htmlrtf }\htmlrtf0 {\*\htmltag4 \par }\htmlrtf \htmlrtf0 {\*\htmltag72}\htmlrtf\par}\htmlrtf0 {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag96 <div class="me-email-text" lang="en-US" style="color:#252424;font-family:'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;">}\htmlrtf {\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag96 <div style="margin-top:24px;margin-bottom:20px;">}\htmlrtf {\htmlrtf0 {\*\htmltag64}\htmlrtf {\htmlrtf0 {\*\htmltag148 <span style="font-size:24px;color:#252424;">}\htmlrtf {\htmlrtf0 Microsoft Teams meeting {\*\htmltag156 </span>}\htmlrtf }\htmlrtf0 {\*\htmltag4 \par }\htmlrtf \htmlrtf0 {\*\htmltag72}\htmlrtf\par}\htmlrtf0 {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag96 <div style="margin-bottom:20px;">}\htmlrtf {\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag96 <div style="margin-top:0px;margin-bottom:0px;font-weight:bold;">}\htmlrtf {\htmlrtf0 {\*\htmltag64}\htmlrtf {\htmlrtf0 {\*\htmltag148 <span style="font-size:14px;color:#252424;">}\htmlrtf {\htmlrtf0 Join on your computer or mobile app {\*\htmltag156 </span>}\htmlrtf }\htmlrtf0 {\*\htmltag4 \par }\htmlrtf \htmlrtf0 {\*\htmltag72}\htmlrtf\par}\htmlrtf0 {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par }{\*\htmltag64}\htmlrtf {\htmlrtf0 {} {\*\htmltag84 <a href="https://teams.microsoft.com/l/meetup-join/19%3ameeting_NmEzYjM0YTAtMzljNC00YWUyLTk0NWQtYmQxYTAxNWRhOWFi%40thread.v2/0?context=%7b%22Tid%22%3a%2204930c22-8e5a-4c3c-88d9-5d040b723d74%22%2c%22Oid%22%3a%2265834454-14e9-4f1e-9b41-3a214f3f285c%22%7d" class="me-email-headline" style="font-size:14px;font-family:'Segoe UI Semibold','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;text-decoration:underline;color:#6264a7;" title="https://teams.microsoft.com/l/meetup-join/19%3ameeting_nmezyjm0ytatmzljnc00ywuyltk0nwqtymqxytaxnwrhowfi%40thread.v2/0?context=%7b%22tid%22%3a%2204930c22-8e5a-4c3c-88d9-5d040b723d74%22%2c%22oid%22%3a%2265834454-14e9-4f1e-9b41-3a214f3f285c%22%7d" target="_blank" rel="noreferrer noopener">}\htmlrtf {\field{\*\fldinst{HYPERLINK "https://teams.microsoft.com/l/meetup-join/19%3ameeting_NmEzYjM0YTAtMzljNC00YWUyLTk0NWQtYmQxYTAxNWRhOWFi%40thread.v2/0?context=%7b%22Tid%22%3a%2204930c22-8e5a-4c3c-88d9-5d040b723d74%22%2c%22Oid%22%3a%2265834454-14e9-4f1e-9b41-3a214f3f285c%22%7d" \n}}{\fldrslt\cf1\ul \htmlrtf0 Click {\*\htmltag4 \par }\htmlrtf \htmlrtf0 {\*\htmltag4 }here to join the meeting\htmlrtf }\htmlrtf0 \htmlrtf }\htmlrtf0 {\*\htmltag92 </a>} {\*\htmltag72}\htmlrtf\par}\htmlrtf0 {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag96 <div style="margin-bottom:24px;margin-top:20px;">}\htmlrtf {\htmlrtf0 {\*\htmltag64}\htmlrtf {\htmlrtf0 {} {\*\htmltag84 <a href="https://aka.ms/JoinTeamsMeeting" class="me-email-link" style="font-size:14px;text-decoration:underline;color:#6264a7;font-family:'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;" title="https://aka.ms/jointeamsmeeting" target="_blank" rel="noreferrer noopener">}\htmlrtf {\field{\*\fldinst{HYPERLINK "https://aka.ms/JoinTeamsMeeting" \n}}{\fldrslt\cf1\ul \htmlrtf0 Learn {\*\htmltag4 \par }\htmlrtf \htmlrtf0 {\*\htmltag4 }More\htmlrtf }\htmlrtf0 \htmlrtf }\htmlrtf0 {\*\htmltag92 </a>} | {} {\*\htmltag84 <a href="https://teams.microsoft.com/meetingOptions/?organizerId=65834454-14e9-4f1e-9b41-3a214f3f285c&amp;tenantId=04930c22-8e5a-4c3c-88d9-5d040b723d74&amp;threadId=19_meeting_NmEzYjM0YTAtMzljNC00YWUyLTk0NWQtYmQxYTAxNWRhOWFi@thread.v2&amp;messageId=0&amp;language=en-US" class="me-email-link" style="font-size:14px;text-decoration:underline;color:#6264a7;font-family:'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;" title="https://teams.microsoft.com/meetingoptions/?organizerid=65834454-14e9-4f1e-9b41-3a214f3f285c&amp;tenantid=04930c22-8e5a-4c3c-88d9-5d040b723d74&amp;threadid=19_meeting_nmezyjm0ytatmzljnc00ywuyltk0nwqtymqxytaxnwrhowfi@thread.v2&amp;messageid=0&amp;language=en-us" target="_blank" rel="noreferrer noopener">}\htmlrtf {\field{\*\fldinst{HYPERLINK "https://teams.microsoft.com/meetingOptions/?organizerId=65834454-14e9-4f1e-9b41-3a214f3f285c&tenantId=04930c22-8e5a-4c3c-88d9-5d040b723d74&threadId=19_meeting_NmEzYjM0YTAtMzljNC00YWUyLTk0NWQtYmQxYTAxNWRhOWFi@thread.v2&messageId=0&language=en-US" \n}}{\fldrslt\cf1\ul \htmlrtf0 {\*\htmltag4 \par }Meeting options\htmlrtf }\htmlrtf0 \htmlrtf }\htmlrtf0 {\*\htmltag92 </a>} {\*\htmltag72}\htmlrtf\par}\htmlrtf0 {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag96 <div style="font-size:14px;margin-bottom:4px;font-family:'Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;">}\htmlrtf {\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag96 <div style="font-size:12px;">}\htmlrtf {\htmlrtf0 {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag96 <div style="width:100%;height:20px;">}\htmlrtf {\htmlrtf0 {\*\htmltag64}\htmlrtf {\htmlrtf0 {\*\htmltag148 <span style="white-space:nowrap;color:#5F5F5F;opacity:.36;">}\htmlrtf {\htmlrtf0 ________________________________________________________________________________ {\*\htmltag156 </span>}\htmlrtf }\htmlrtf0 {\*\htmltag4 \par }\htmlrtf \htmlrtf0 {\*\htmltag72}\htmlrtf\par}\htmlrtf0 {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag96 <div>}\htmlrtf {\htmlrtf0 {\*\htmltag104 </div>}\htmlrtf }\htmlrtf0 {\*\htmltag0 \par } {\*\htmltag58 </body>} {\*\htmltag2 \par } {\*\htmltag27 </html>} {\*\htmltag3 \par }}
解决方案
针对这种内嵌HTML的RTF,有三种可靠的实现方式:
方法1:正则表达式提取(轻量无依赖)
观察RTF结构可知,所有HTML标签都包裹在{\*\htmltag\d+ (.*?)}格式块中,文本内容则出现在\htmlrtf0之后、下一个RTF标签之前。通过正则匹配提取这些内容,再拼接成完整HTML:
using System; using System.Text.RegularExpressions; public class RtfHtmlExtractor { public static string ExtractHtmlFromRtf(string rtfContent) { // 提取所有htmltag中的HTML标签 var htmlTagMatches = Regex.Matches(rtfContent, @"\{\*\\htmltag\d+ (.*?)\}", RegexOptions.Singleline); // 提取所有htmlrtf0后的文本内容 var textMatches = Regex.Matches(rtfContent, @"\htmlrtf0\s*(.*?)(?=\\htmlrtf|\{\*\\htmltag|\z)", RegexOptions.Singleline); var htmlBuilder = new System.Text.StringBuilder(); int textIndex = 0; foreach (Match tagMatch in htmlTagMatches) { string tagContent = tagMatch.Groups[1].Value; // 替换RTF转义字符 tagContent = tagContent.Replace(""", "\"") .Replace("<", "<") .Replace(">", ">"); htmlBuilder.Append(tagContent); // 追加对应文本内容 if (textIndex < textMatches.Count) { string textContent = textMatches[textIndex].Groups[1].Value.Trim(); // 去除RTF格式标记 textContent = Regex.Replace(textContent, @"\\par\s*", "\n"); if (!string.IsNullOrWhiteSpace(textContent)) { htmlBuilder.Append(textContent); } textIndex++; } } // 清理多余换行和空格 string finalHtml = Regex.Replace(htmlBuilder.ToString(), @"\n\s*\n", "\n"); return finalHtml.Trim(); } }
方法2:使用WinForms RichTextBox控件(适配复杂RTF)
利用.NET自带的RichTextBox加载RTF后导出为HTML,能处理包含复杂格式的RTF内容:
using System.Windows.Forms; using System.IO; public class RtfHtmlConverter { public static string ConvertRtfToHtml(string rtfContent) { using (var richTextBox = new RichTextBox()) { richTextBox.Rtf = rtfContent; using (var htmlStream = new MemoryStream()) { richTextBox.SaveFile(htmlStream, RichTextBoxStreamType.Html); htmlStream.Seek(0, SeekOrigin.Begin); using (var reader = new StreamReader(htmlStream)) { return reader.ReadToEnd(); } } } } }
注意:该方法需引用
System.Windows.Forms程序集,控制台或ASP
相关产品推荐
相关产品推荐

