65.9K
CodeProject 正在变化。 阅读更多。
Home

清理 RTF 合并字段

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (5投票s)

2008年2月9日

CPOL

3分钟阅读

viewsIcon

45729

downloadIcon

348

用于清理/移除 (RTF) 文档中自定义合并域 RTF 代码的类。

  • 下载源代码 - 2.04 KB
  • 很抱歉内联注释中有很多荷兰语,我会尝试在某个时候移除(改进)它们。

引言

RTF 对我来说一直是个麻烦;它如此诱人,因为它都是纯文本,因此是“人类”可读的,但请稍等...尝试修改第 x 行上字符串的字体...好吧,说实话... 甚至不要尝试。

好吧,RTF 对我来说仍然很诱人,尤其是在涉及到用户、文档以及是的:邮件/文档合并时!

好吧,让我们切入正题。这段代码在我使用 RTF 文档、将其发布到网站并期望其自定义字段使用来自任何来源的数据(地址、个人姓名或……奇怪的花名)更新时,对我有帮助。

这个特定的类期望输入是字符串(构建器),以及一个开始和结束字符。它在输入字符串中搜索一对这些字符,删除它们之间的所有 RTF 代码,并返回完整 RTF 字符串的清理版本。

此外,还可以使用更改数组。

背景

问题主要在于 Word X 版本如何制作、修改和重建 RTF 文档。

(这不是对写字板或任何其他 RTF 编辑器的欢呼,但它们在将 RTF 重建为比 MS Word 更简单和更直接的代码方面绝对做得更好。)

如果您希望用户在其文档中使用像这样的合并域:[this_is_a_merge_field] 并将其替换为您自己的数据库字段,那么即使在用户不小心更改字体然后删除合并字段字符串之间,Word 中也存在问题。

您希望它在 RTF 代码中显示为纯粹简单的:[this_is_a_merge_field]

但相反,它会变成这样:[this_is_a_}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15991329\charrsid3492762 merge}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15991329 _field]

好吧,我们的简单 String.Replace 无法在该字符串中找到我们的“this_is_a_merge_field”数据库字段。所以...我们制作了一些处理这个问题的东西!

使用代码

基本代码放入一个字符串(构建器)。 如果您愿意,可以提供一些开始和结束字符,例如 [ ] 或 < >,甚至 # %([ 和 ] 是默认值)。 不要在其中放入 { } 或管道 |,因为这些是 RTF 代码或将被替换

这是主要子程序。 放入一个字符串(构建器),并期望输出一个清理后的字符串(构建器)

Public Function CleanDocument(ByVal rtfSring As String, _
       Optional ByVal detectStartChar As Char = CChar("["),_
       Optional ByVal detectEndChar As Char = CChar("]")) As String

    Dim time As Integer = Date.Now.TimeOfDay.Milliseconds

    Dim sb As New StringBuilder(rtfSring)
    Dim sbclean As New StringBuilder(sb.ToString)
    Dim tempstr(1) As String
    Dim stepper As Integer = 0
    Do
        tempstr = ReturnNextRtfString(sb, detectStartChar, detectEndChar, True)
        
        If tempstr(0) Is Nothing Then Exit Do
        sbclean.Replace(tempstr(0), tempstr(1))
        
        ReDim Preserve _ArrayOfFields(1, stepper)
        _ArrayOfFields(0, stepper) = tempstr(0)
        _ArrayOfFields(1, stepper) = tempstr(1)
        stepper += 1
    Loop

    processedinmillisecconds = Date.Now.TimeOfDay.Milliseconds - time

    Return sbclean.ToString

End Function

现在,辅助子程序查找每个带有开始和结束字符的子字符串

Private Function ReturnNextRtfString(ByRef sb As StringBuilder, _
        ByVal startchar As Char, ByVal endchar As Char, _
        Optional ByVal autoclean As Boolean = False) As String()

    Dim startcounter, endcounter As Integer
    Dim acounter As Integer
    Dim returnstring(1) As String
    
    For acounter = bcounter To sb.Length - 1
         
        If sb.Chars(acounter) = startchar Then
            startcounter = acounter
        End If
        
        If sb.Chars(acounter) = endchar Then
            endcounter = acounter + 1
            'set nieuwe start voor de volgende aanroep van de functie
            bcounter = acounter + 1
        End If
        
        If startcounter > 0 AndAlso endcounter > startcounter Then
           
            If autoclean = True Then
                returnstring(1) = CleanRtfString(sb.ToString.Substring
                (startcounter, endcounter - startcounter))
                    returnstring(0) = sb.ToString.Substring(startcounter, 
        endcounter - startcounter)
                Return returnstring
            Else
                returnstring(0) = sb.ToString.Substring(startcounter, 
        endcounter - startcounter)
                Return returnstring
            End If

            Exit Function
        End If
    Next
    Return returnstring
End Function

最后,是清理函数

Private Function CleanRtfString(ByRef rtfstring As String) As String
    Dim sb As New StringBuilder(rtfstring)
    Dim cleansb As New StringBuilder

    Dim ccounter As Integer

    For ccounter = 0 To sb.Length
 
        If Asc(sb.Chars(ccounter)) > 32 AndAlso sb.Chars(ccounter) <> "|" _
           AndAlso sb.Chars(ccounter) <> "\" AndAlso sb.Chars(ccounter) <> "{" _
           AndAlso sb.Chars(ccounter) <> "}" Then
               cleansb.Append(sb.Chars(ccounter))
        End If

        If ccounter + 1 >= sb.Length Then Exit For
       
        If sb.Chars(ccounter + 1) = "\" OrElse sb.Chars(ccounter + 1) = "{" 
        OrElse sb.Chars(ccounter + 1) = "}" Then
            For dcounter As Integer = ccounter + 1 To sb.Length - 1
                If sb.Chars(dcounter) = CChar(" ") Then Exit For
                    sb.Chars(dcounter) = CChar("|")
            Next
        End If
    Next
   
    cleansb.Replace("|", "")
    Return cleansb.ToString
End Function

需要解决的问题

  • 当用户在合并域的标签之间插入图像时,清理器将无法正确清理它。
  • 当 Word 超链接位于标签之间时,这也会破坏输出。
  • 由于管道字符用作替换,因此不能在字段中使用它。
  • 空格是 RTF 中唯一的标识符,因此作为一个简单的解决方案,我删除了它们;这可以做得更整洁。

历史

这是我在 The Code Project 上的第一篇文章!

  • 2008-02-10:第一个版本。
© . All rights reserved.