【问题标题】:How to convert a string to RTF in C#?如何在 C# 中将字符串转换为 RTF?
【发布时间】:2011-01-25 15:58:49
【问题描述】:

问题

如何将字符串“Européen”转换为 RTF 格式的字符串“Europ\'e9en”?

[TestMethod]
public void Convert_A_Word_To_Rtf()
{
    // Arrange
    string word = "Européen";
    string expected = "Europ\'e9en";
    string actual = string.Empty;

    // Act
    // actual = ... // How?

    // Assert
    Assert.AreEqual(expected, actual);
}

到目前为止我发现了什么

富文本框

RichTextBox 可用于某些事情。示例:

RichTextBox richTextBox = new RichTextBox();
richTextBox.Text = "Européen";
string rtfFormattedString = richTextBox.Rtf;

但是 rtfFormattedString 原来是整个 RTF 格式的文档,而不仅仅是字符串“Europ\'e9en”。

堆栈溢出

谷歌

我还在网上找到了很多其他资源,但没有一个能完全解决我的问题。

回答

Brad Christie's answer

必须添加 Trim() 以删除 result 中的前面空格。除此之外,Brad Christie 的解决方案似乎奏效了。

我现在会使用这个解决方案,尽管我的直觉很糟糕,因为我们必须使用 SubString 并修剪 RichTextBox 以获得 RTF 格式的字符串。

测试用例:

[TestMethod]
public void Test_To_Verify_Brad_Christies_Stackoverflow_Answer()
{
        Assert.AreEqual(@"Europ\'e9en", "Européen".ConvertToRtf());
        Assert.AreEqual(@"d\'e9finitif", "définitif".ConvertToRtf());
        Assert.AreEqual(@"\'e0", "à".ConvertToRtf());
        Assert.AreEqual(@"H\'e4user", "Häuser".ConvertToRtf());
        Assert.AreEqual(@"T\'fcren", "Türen".ConvertToRtf());
        Assert.AreEqual(@"B\'f6den", "Böden".ConvertToRtf());
}

逻辑作为扩展方法:

public static class StringExtensions
{
    public static string ConvertToRtf(this string value)
    {
        RichTextBox richTextBox = new RichTextBox();
        richTextBox.Text = value;
        int offset = richTextBox.Rtf.IndexOf(@"\f0\fs17") + 8; // offset = 118;
        int len = richTextBox.Rtf.LastIndexOf(@"\par") - offset;
        string result = richTextBox.Rtf.Substring(offset, len).Trim();
        return result;
    }
}

【问题讨论】:

  • @Abe Miessler:我看到了这个问题,并在上​​面的问题中添加了链接。但是,我不太明白这如何解决我的问题(它可能会,但我不明白)。您能否提供一个使上述测试方法通过的代码 sn-p?
  • 再次查看我的答案,我已经为您的问题发布了一个(hacky)解决方案。我希望你只是翻译一些次要/更简单的东西。
  • @Lernkurve:看到有人对此投了赞成票,我想我会跟进;这仍然有效吗? (我有点好奇这种方法有多不安全)
  • @BradChristie:我真的无法告诉你这种方法有多不安全。我们没有检查它是否适用于每一种可能的情况。但由于我们不确定,我们为所有我们感兴趣的特殊字符编写了测试,并且对这些特殊字符非常有效。

标签: c# rtf


【解决方案1】:

RichTextBox 不是总是有相同的页眉/页脚吗?您可以根据偏移位置读取内容,然后继续使用它进行解析。 (我认为?如果我错了,请纠正我)

有可用的库,但我个人从来没有好运过它们(尽管总是在完全用尽可能性之前找到另一种方法)。此外,大多数较好的通常都包含象征性的费用。


编辑
有点像 hack,但这应该能让你完成你需要完成的事情(我希望):

RichTextBox rich = new RichTextBox();
Console.Write(rich.Rtf);

String[] words = { "Européen", "Apple", "Carrot", "Touché", "Résumé", "A Européen eating an apple while writing his Résumé, Touché!" };
foreach (String word in words)
{
    rich.Text = word;
    Int32 offset = rich.Rtf.IndexOf(@"\f0\fs17") + 8;
    Int32 len = rich.Rtf.LastIndexOf(@"\par") - offset;
    Console.WriteLine("{0,-15} : {1}", word, rich.Rtf.Substring(offset, len).Trim());
}

编辑 2

breakdown of the codes RTF control code如下:

  • 标题
    • \f0 - 使用 0-index 字体(列表中的第一个字体,通常是 Microsoft Sans Serif(在标题中的字体表中注明:{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}))
    • \fs17 - 字体格式,指定大小为 17(17 为半点)
  • 页脚
    • \par 指定它是段落的结尾。

希望这可以解决一些问题。 ;-)

【讨论】:

  • 如果标头的长度发生变化,您的方法将失败。如果标题包含字符串“!!@@!!”,我的方法将失败(但如果输入字符串包含“!!@@!!”则不会失败)。
  • @Brian:我的标题确实发生了变化。输出“Apple”和“Européen”之间的区别使标题发生变化。
  • @Brad Christie:我的意思是如果 "\fo\fs17" 发生变化。我承认这不太可能。我想我只是厌恶依赖于实现细节。
  • @Brad Christie:我已将您的代码添加到我上面的帖子中,它似乎有效。谢谢。 :-) 在尝试了更多并弄清楚你在那里实际做了什么之后,我会报告回来。 ;-) 也许您可以通过解释 @"\f0\fs17" 和 @"\par" 代表什么来帮助我,因为我不知道 RTF 规范。
  • @Lernkurve:再次更新答案,请看底部。 ;-)
【解决方案2】:

我找到了一个很好的解决方案,它实际上使用 RichTextBox 本身进行转换:

private static string FormatAsRTF(string DirtyText)
{
    System.Windows.Forms.RichTextBox rtf = new System.Windows.Forms.RichTextBox();
    rtf.Text = DirtyText;
    return rtf.Rtf;
}

http://www.baltimoreconsulting.com/blog/development/easily-convert-a-string-to-rtf-in-net/

【讨论】:

  • 我上面显示的单元测试因您的转换代码而失败。
【解决方案3】:

我就是这样去的:

private string ConvertString2RTF(string input)
{
    //first take care of special RTF chars
    StringBuilder backslashed = new StringBuilder(input);
    backslashed.Replace(@"\", @"\\");
    backslashed.Replace(@"{", @"\{");
    backslashed.Replace(@"}", @"\}");

    //then convert the string char by char
    StringBuilder sb = new StringBuilder();
    foreach (char character in backslashed.ToString())
    {
        if (character <= 0x7f)
            sb.Append(character);
        else
            sb.Append("\\u" + Convert.ToUInt32(character) + "?");
    }
    return sb.ToString();
}

我认为使用RichTextBox 是:
1) 矫枉过正
2) 我不喜欢RichTextBox,因为我花了几天的时间试图让它与在 Word 中创建的 RTF 文档一起工作。

【讨论】:

    【解决方案4】:

    下面是一个将字符串转换为 RTF 字符串的丑陋示例:

    class Program
    {
        static RichTextBox generalRTF = new RichTextBox();
    
        static void Main()
        {
            string foo = @"Européen";
            string output = ToRtf(foo);
            Trace.WriteLine(output);
        }
    
        private static string ToRtf(string foo)
        {
            string bar = string.Format("!!@@!!{0}!!@@!!", foo);
            generalRTF.Text = bar;
            int pos1 = generalRTF.Rtf.IndexOf("!!@@!!");
            int pos2 = generalRTF.Rtf.LastIndexOf("!!@@!!");
            if (pos1 != -1 && pos2 != -1 && pos2 > pos1 + "!!@@!!".Length)
            {
                pos1 += "!!@@!!".Length;
                return generalRTF.Rtf.Substring(pos1, pos2 - pos1);
            }
            throw new Exception("Not sure how this happened...");
        }
    }
    

    【讨论】:

    • 感谢您花时间发布代码。我得看看它。感叹号看起来很吓人...
    • @Lernkurve:“!!@@!!”是一个任意分隔符,真正属于const String
    • 感谢您的解释。我自己应该看到的。 :-)
    • @Lernkurve:基本上,我的解决方案和 Brad 的解决方案是相同的,但是 brad 使用RichTextBox 控件的自然出现的文本来分隔文本,而我自己生成分隔符。我还添加了一些错误检查,以防出现“不可能”的情况。这种检查是否合适还有待商榷。
    【解决方案5】:

    我知道已经有一段时间了,希望这会有所帮助..

    在尝试了我可以使用的每个转换代码后,此代码对我有用:

    titleText 和 contentText 是填充在常规 TextBox 中的简单文本

    var rtb = new RichTextBox();
    rtb.AppendText(titleText)
    rtb.AppendText(Environment.NewLine);
    rtb.AppendText(contentText)
    
    rtb.Refresh();
    

    rtb.rtf 现在包含 rtf 文本。

    以下代码将保存 rtf 文本并允许您打开文件,对其进行编辑,然后再次将其加载回 RichTextBox:

    rtb.SaveFile(path, RichTextBoxStreamType.RichText);
    

    【讨论】:

      【解决方案6】:

      这是改进的@Vladislav Zalesak 的回答:

      public static string ConvertToRtf(string text)
      {
          // using default template from wiki
          StringBuilder sb = new StringBuilder(@"{\rtf1\ansi\ansicpg1250\deff0{\fonttbl\f0\fswiss Helvetica;}\f0\pard ");
          foreach (char character in text)
          {
              if (character <= 0x7f)
              {
                  // escaping rtf characters
                  switch (character)
                  {
                      case '\\':
                      case '{':
                      case '}':
                          sb.Append('\\');
                          break;
                      case '\r':
                          sb.Append("\\par");
                          break;
                  }
      
                  sb.Append(character);
              }
              // converting special characters
              else
              {
                  sb.Append("\\u" + Convert.ToUInt32(character) + "?");
              }
          }
          sb.Append("}");
          return sb.ToString();
      }
      

      【讨论】:

        【解决方案7】:

        不是最优雅,但相当优化和快速的方法:

        public static string PlainTextToRtf(string plainText)
        {
            if (string.IsNullOrEmpty(plainText))
                return "";
        
            string escapedPlainText = plainText.Replace(@"\", @"\\").Replace("{", @"\{").Replace("}", @"\}");
            escapedPlainText = EncodeCharacters(escapedPlainText);
        
            string rtf = @"{\rtf1\ansi\ansicpg1250\deff0{\fonttbl\f0\fswiss Helvetica;}\f0\pard ";
            rtf += escapedPlainText.Replace(Environment.NewLine, "\\par\r\n ") + ;
            rtf += " }";
            return rtf;
        }
        

        .

        编码字符(波兰语)方法:

        private static string EncodeCharacters(string text)
        {
            if (string.IsNullOrEmpty(text))
                return "";
        
            return text
                .Replace("ą", @"\'b9")
                .Replace("ć", @"\'e6")
                .Replace("ę", @"\'ea")
                .Replace("ł", @"\'b3")
                .Replace("ń", @"\'f1")
                .Replace("ó", @"\'f3")
                .Replace("ś", @"\'9c")
                .Replace("ź", @"\'9f")
                .Replace("ż", @"\'bf")
                .Replace("Ą", @"\'a5")
                .Replace("Ć", @"\'c6")
                .Replace("Ę", @"\'ca")
                .Replace("Ł", @"\'a3")
                .Replace("Ń", @"\'d1")
                .Replace("Ó", @"\'d3")
                .Replace("Ś", @"\'8c")
                .Replace("Ź", @"\'8f")
                .Replace("Ż", @"\'af");
        }
        

        【讨论】:

        • 用你的解决方案,你怎么知道你已经覆盖了所有可能的特殊字符?如果一个字符不在你的 EncodeCharacters 的替换列表中,那么它就会出错,对吧?
        • 在一些罕见的例外情况下,这个小技巧可能是最后的手段。
        猜你喜欢
        • 2021-12-22
        • 2021-11-17
        • 2019-01-16
        • 2022-10-05
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        • 2011-01-21
        相关资源
        最近更新 更多