C#:用于解码Quoted-Printable编码的类?

Lop*_*per 26 c# string encoding class quoted-printable

C#中是否存在可以将Quoted-Printable编码转换为String?的现有类?单击上面的链接以获取有关编码的更多信息.

为方便起见,以上链接引用了以下内容.

任何8位字节的值可以与3个字符,被编码的"="随后两个十六进制数字(0-9或A-F)表示的字节的数值.例如,US-ASCII换页符(十进制值12)可以用"= 0C"表示,US-ASCII等号(十进制值61)用"= 3D"表示.除了可打印的ASCII字符或行尾字符之外的所有字符都必须以这种方式编码.

除"="(十进制61)外,所有可打印的ASCII字符(33到126之间的十进制值)可以由它们自己表示.

ASCII选项卡和空格字符,十进制值9和32,可以由它们自己表示,除非这些字符出现在一行的末尾.如果其中一个字符出现在一行的末尾,则必须将其编码为"= 09"(制表符)或"= 20"(空格).

如果正在编码的数据包含有意义的换行符,则必须将它们编码为ASCII CR LF序列,而不是其原始字节值.相反,如果字节值13和10具有除行尾之外的含义,则它们必须被编码为= 0D和= 0A.

引用可打印编码数据的行不得超过76个字符.为了在不改变编码文本的情况下满足该要求,可以根据需要添加软换行符.软换行符在编码行的末尾包含"=",并且不会在解码的文本中导致换行符.

Dav*_*ave 19

框架库中有一些功能可以做到这一点,但它看起来并没有干净利落.实现在内部类中System.Net.Mime.QuotedPrintableStream.这个类定义了一个叫做DecodeBytes你想要的方法.该方法似乎仅由一种用于解码MIME头的方法使用.此方法也是内部的,但在几个地方相当直接调用,例如Attachment.Namesetter.示范:

using System;
using System.Net.Mail;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Attachment attachment = Attachment.CreateAttachmentFromString("", "=?iso-8859-1?Q?=A1Hola,_se=F1or!?=");
            Console.WriteLine(attachment.Name);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

产生输出:

¡HOLA,_señor!

您可能必须进行一些测试以确保正确处理回车等,尽管我们似乎做了一个快速测试.但是,依赖此功能可能不明智,除非您的用例足够接近解码MIME头字符串,您认为它不会被对库所做的任何更改破坏.你可能最好编写自己的引用可打印解码器.

  • 这不会为我转换= 3D等,并且codeproject版本在解码时失败. (6认同)

小智 18

我扩展了Martin Murphy的解决方案,我希望它能适用于所有情况.

private static string DecodeQuotedPrintables(string input, string charSet)
{           
    if (string.IsNullOrEmpty(charSet))
    {
        var charSetOccurences = new Regex(@"=\?.*\?Q\?", RegexOptions.IgnoreCase);
        var charSetMatches = charSetOccurences.Matches(input);
        foreach (Match match in charSetMatches)
        {
            charSet = match.Groups[0].Value.Replace("=?", "").Replace("?Q?", "");
            input = input.Replace(match.Groups[0].Value, "").Replace("?=", "");
        }
    }

    Encoding enc = new ASCIIEncoding();
    if (!string.IsNullOrEmpty(charSet))
    {
        try
        {
            enc = Encoding.GetEncoding(charSet);
        }
        catch
        {
            enc = new ASCIIEncoding();
        }
    }

    //decode iso-8859-[0-9]
    var occurences = new Regex(@"=[0-9A-Z]{2}", RegexOptions.Multiline);
    var matches = occurences.Matches(input);
    foreach (Match match in matches)
    {
        try
        {
            byte[] b = new byte[] { byte.Parse(match.Groups[0].Value.Substring(1), System.Globalization.NumberStyles.AllowHexSpecifier) };
            char[] hexChar = enc.GetChars(b);
            input = input.Replace(match.Groups[0].Value, hexChar[0].ToString());
        }
        catch { }
    }

    //decode base64String (utf-8?B?)
    occurences = new Regex(@"\?utf-8\?B\?.*\?", RegexOptions.IgnoreCase);
    matches = occurences.Matches(input);
    foreach (Match match in matches)
    {
        byte[] b = Convert.FromBase64String(match.Groups[0].Value.Replace("?utf-8?B?", "").Replace("?UTF-8?B?", "").Replace("?", ""));
        string temp = Encoding.UTF8.GetString(b);
        input = input.Replace(match.Groups[0].Value, temp);
    }

    input = input.Replace("=\r\n", "");
    return input;
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢你...它解决了我的问题,这就是我要找的好几个小时.. (2认同)
  • 不支持这一行中的=和回车"如果你相信真相= 3Dbeauty,那么肯定= \nmathematics是哲学中最美丽的分支." (2认同)

Mar*_*phy 7

我写得很快.

    public static string DecodeQuotedPrintables(string input)
    {
        var occurences = new Regex(@"=[0-9A-H]{2}", RegexOptions.Multiline);
        var matches = occurences.Matches(input);
        var uniqueMatches = new HashSet<string>(matches);
        foreach (string match in uniqueMatches)
        {
            char hexChar= (char) Convert.ToInt32(match.Substring(1), 16);
            input =input.Replace(match, hexChar.ToString());
        }
        return input.Replace("=\r\n", "");
    }       
Run Code Online (Sandbox Code Playgroud)


Lee*_*ris 6

我一直在寻找动态解决方案,并花了 2 天尝试不同的解决方案。该解决方案将支持日语字符和其他标准字符集

private static string Decode(string input, string bodycharset) {
        var i = 0;
        var output = new List<byte>();
        while (i < input.Length) {
            if (input[i] == '=' && input[i + 1] == '\r' && input[i + 2] == '\n') {
                //Skip
                i += 3;
            } else if (input[i] == '=') {
                string sHex = input;
                sHex = sHex.Substring(i + 1, 2);
                int hex = Convert.ToInt32(sHex, 16);
                byte b = Convert.ToByte(hex);
                output.Add(b);
                i += 3;
            } else {
                output.Add((byte)input[i]);
                i++;
            }
        }


        if (String.IsNullOrEmpty(bodycharset))
            return Encoding.UTF8.GetString(output.ToArray());
        else {
            if (String.Compare(bodycharset, "ISO-2022-JP", true) == 0)
                return Encoding.GetEncoding("Shift_JIS").GetString(output.ToArray());
            else
                return Encoding.GetEncoding(bodycharset).GetString(output.ToArray());
        }

    }
Run Code Online (Sandbox Code Playgroud)

然后你可以调用该函数

Decode("=E3=82=AB=E3=82=B9=E3", "utf-8")
Run Code Online (Sandbox Code Playgroud)

这最初是在这里找到的


小智 5

如果您要使用UTF-8编码解码带引号的可打印字符,则需要注意,不能同时解码每个带引号的可打印序列,因为如果同时存在多个带​​引号的可打印字符,则无法一次解码每个带引号的可打印序列。

例如-如果您具有以下序列= E2 = 80 = 99并一次使用UTF8对其进行解码,则会得到三个“怪异”字符-如果您改为构建一个由三个字节组成的数组,并用如果使用UTF8编码,您将得到一个单胶体。

显然,如果您使用的是ASCII编码,那么一次一次就没问题,但是解码运行意味着您的代码将可以使用,而与所使用的文本编码器无关。

哦,别忘了= 3D是一种特殊情况,这意味着您需要再解码一次,这真是一个疯狂的陷阱!

希望能有所帮助

  • 是的,这更接近[Skeet在这里的答案](http://stackoverflow.com/a/3289987/1028230)。我们应该将Quoted Printable视为不是字符,而是将字节序列化的一种方法。首先解码为字节,然后将该字节数组解码为字符串以进行编码-`System.Text.Encoding.UTF8.GetString(byteArray)`或您所拥有的。尝试从小于128的字节中“抢救”字符是头线程错误。 (2认同)