【问题标题】:How to convert Quoted-Print String如何转换引用打印字符串
【发布时间】:2016-09-29 03:27:32
【问题描述】:

我正在 .NET 中处理法语字符串 解码邮件正文,我收到“Chasn=C3=A9 sur illet” 我想得到“Chasné sur illet” 而且我在 2 天的网络搜索中找不到任何解决方案。

C# 或 VB.NET 谁能帮帮我?

谢谢

【问题讨论】:

  • 你能在你设置字符串的地方发布你的代码吗?
  • 您好,我的字符串来自 IMAP 服务器 我阅读了消息并使用 IMAP 命令获取消息正文文本:FETCH BODY[TEXT] 它返回给我一个以 Quoted_printable 格式编码的字符串,但我没有'找不到任何想法做转换器
  • @MarcCollin 请参阅下面的完整代码。

标签: c# vb.net mime quoted-printable


【解决方案1】:

这是 UTF8 编码。

使用这篇文章:

http://www.dpit.co.uk/decoding-quoted-printable-email-in-c/

这是代码(如果有帮助别忘了接受答案):

using System;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine(DecodeQuotedPrintable("Chasn=C3=A9 sur illet"));
            Console.ReadKey();
        }

        static string DecodeQuotedPrintable(string input)
        {
            var occurences = new Regex(@"(=[0-9A-Z][0-9A-Z])+", RegexOptions.Multiline);
            var matches = occurences.Matches(input);
            foreach (Match m in matches)
            {
                byte[] bytes = new byte[m.Value.Length / 3];
                for (int i = 0; i < bytes.Length; i++)
                {
                    string hex = m.Value.Substring(i * 3 + 1, 2);
                    int iHex = Convert.ToInt32(hex, 16);
                    bytes[i] = Convert.ToByte(iHex);
                }
                input = input.Replace(m.Value, Encoding.UTF8.GetString(bytes));
            }
            return input.Replace("=rn", "");
        }
    }
}

【讨论】:

    【解决方案2】:
        static string ConverFromHex(string source)
        {
            string target = string.Empty;
    
            int startPos = source.IndexOf('=', 0);
            int prevStartPos = 0;
            while (startPos >= 0)
            {
                // concat with substring from source
                target += source.Substring(prevStartPos, startPos - prevStartPos);
    
                // next offset
                startPos++;
    
                // update prev pos
                prevStartPos = startPos;
    
                // get substring
                string hexString = source.Substring(startPos, 2);
    
                // get int equiv
                int hexNum = 0;
                if (int.TryParse(hexString, System.Globalization.NumberStyles.AllowHexSpecifier, System.Globalization.CultureInfo.InvariantCulture, out hexNum))
                {
                    // add to target string
                    target += (char)hexNum;
    
                    // add hex length
                    prevStartPos += 2;
                }
    
                // next occurence
                startPos = source.IndexOf('=', startPos);
            }
    
            // add rest of source
            target += source.Substring(prevStartPos);
    
            return target;
        }
    

    【讨论】:

    • 这段代码没有正确处理 OP 的字符串,结果是“Chasné sur illet”。您的代码将每个十六进制数字视为一个单独的字符,但“=C3=A9”应该代表单个字符“é”。
    【解决方案3】:

    发件人:https://stackoverflow.com/a/36803911/6403521 我的解决方案:

        [TestMethod]
        public void TestMethod1()
        {
    
            Assert.AreEqual("La Bouichère", quotedprintable("La Bouich=C3=A8re", "utf-8"));
            Assert.AreEqual("Chasné sur illet", quotedprintable("Chasn=C3=A9 sur illet", "utf-8"));
            Assert.AreEqual("é è", quotedprintable("=C3=A9 =C3=A8", "utf-8"));
        }
        private string quotedprintable(string pStrIn, string encoding)
        {
            String strOut = pStrIn.Replace("=\r\n", "");
            // Find the first =
            int position = strOut.IndexOf("=");
            while (position != -1)
            { 
                // String before the =
                string leftpart = strOut.Substring(0, position);
                // get the QuotedPrintable String in a ArrayList
                System.Collections.ArrayList hex = new System.Collections.ArrayList();
                // The first Part
                hex.Add(strOut.Substring(1 + position, 2));
                // Look for the next parts
                while (position + 3 < strOut.Length && strOut.Substring(position + 3, 1) == "=")
                {
                    position = position + 3;
                    hex.Add(strOut.Substring(1 + position, 2));
                }
                // In the hex Array, we have two items 
                // Convert using the GetEncoding Function
                byte[] bytes = new byte[hex.Count];
                for (int i = 0; i < hex.Count; i++)
                {
                    bytes[i] = System.Convert.ToByte(new string(((string)hex[i]).ToCharArray()), 16);
                }
                string equivalent = System.Text.Encoding.GetEncoding(encoding).GetString(bytes);
                // Part of the orignal String after the last QP Symbol
                string rightpart = strOut.Substring(position + 3);
                // Re build the String
                strOut = leftpart + equivalent + rightpart;
                // find the new QP Position
                position = leftpart.Length + equivalent.Length;
                if (rightpart.Length == 0)
                {
                    position = -1;
                }
                else
                {
                    position = strOut.IndexOf("=", position + 1);
                }
            }
            return strOut;
        }
    

    【讨论】:

    • 天哪,这太复杂了。你试过我的答案了吗?
    【解决方案4】:

    或者最简单的,只需使用我的MimeKit 库中的QuotedPrintableDecoder

    static string DecodeQuotedPrintable (string input, string charset)
    {
        var decoder = new QuotedPrintableDecoder ();
        var buffer = Encoding.ASCII.GetBytes (input);
        var output = new byte[decoder.EstimateOutputLength (buffer.Length)];
        int used = decoder.Decode (buffer, 0, buffer.Length, output);
        var encoding = Encoding.GetEncoding (charset);
        return encoding.GetString (output, 0, used);
    }
    

    请注意,上面的其他答案假设解码的内容是 ASCII 或 UTF-8,但不一定是这种情况。您需要从您正在解码的 MIME 部分的 Content-Type 标头中获取 charset 参数。

    当然...如果您不知道如何获取该信息,您可以简单地使用我很棒的 MailKit 库从 IMAP 获取 MIME 部分并让它为您完成所有这些工作。

    【讨论】:

    • MimeKit 看起来不错,但它希望能够加载流对象。我明白为什么总体上会更好,但是如果您现有的代码库无法在文件加载步骤中轻松放入 MimeKit,AFAICT 就没有将它与字符串一起使用的功能。
    • FWIW,并非所有电子邮件都可以正确转换为 C# 字符串。问题是电子邮件可以有多个文本部分,每个文本部分使用不同的字符集编码,这意味着通过将其转换为字符串,它将被损坏。只是让您长期了解的事情。
    【解决方案5】:

    我们在使用这种方法时遇到了问题 - 它非常慢。 以下增强性能A LOT

    public static string FromMailTransferEncoding(this string messageText, Encoding enc, string transferEncoding)
    {
        if (string.IsNullOrEmpty(transferEncoding)) 
            return messageText;
    
        if ("quoted-printable".Equals(transferEncoding.ToLower())) 
        {
            StringBuilder sb = new StringBuilder();               
            string delimitorRegEx = @"=[\r][\n]";
            string[] parts = Regex.Split(messageText, delimitorRegEx);
    
            foreach (string part in parts)
            {
                string subPart = part;
                Regex occurences = new Regex(@"(=[0-9A-Z][0-9A-Z])+", RegexOptions.Multiline);
                MatchCollection matches = occurences.Matches(subPart);
    
                foreach (Match m in matches)
                {
                    byte[] bytes = new byte[m.Value.Length / 3];
                    for (int i = 0; i < bytes.Length; i++)
                    {
                        string hex = m.Value.Substring(i * 3 + 1, 2);
                        int iHex = Convert.ToInt32(hex, 16);
                        bytes[i] = Convert.ToByte(iHex);
                    }
    
                    subPart = occurences.Replace(subPart, enc.GetString(bytes), 1);
                }
    
                sb.Append(subPart);
            }
            return sb.ToString();
        }        
    return messageText;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-14
      • 1970-01-01
      • 2013-09-08
      • 2021-11-21
      • 2020-12-19
      • 2019-06-18
      • 1970-01-01
      • 2022-01-13
      相关资源
      最近更新 更多