29

Quoted-Printableエンコーディングを に変換できる C# の既存のクラスはありStringますか? エンコーディングの詳細については、上記のリンクをクリックしてください。

以下、参考までに上記リンクより引用。

任意の 8 ビットのバイト値は、「=」の後にバイトの数値を表す 2 つの 16 進数 (0 ~ 9 または A ~ F) が続く 3 文字でエンコードできます。たとえば、US-ASCII フォーム フィード文字 (10 進値 12) は「=0C」で表すことができ、US-ASCII 等号 (10 進値 61) は「=3D」で表すことができます。印刷可能な ASCII 文字または行末文字を除くすべての文字は、この方法でエンコードする必要があります。

すべての印刷可能な ASCII 文字 (33 から 126 までの 10 進数値) は、「=」(10 進数の 61) を除いて、それ自体で表すことができます。

ASCII タブおよびスペース文字、10 進値 9 および 32 は、これらの文字が行末にある場合を除き、単独で表すことができます。これらの文字のいずれかが行末にある場合は、"=09" (タブ) または "=20" (スペース) としてエンコードする必要があります。

エンコードされるデータに意味のある改行が含まれている場合は、元のバイト値としてではなく、ASCII CR LF シーケンスとしてエンコードする必要があります。逆に、バイト値 13 と 10 が行末以外の意味を持つ場合は、=0D と =0A としてエンコードする必要があります。

quoted-printable エンコード データの行は、76 文字を超えてはなりません。エンコードされたテキストを変更せずにこの要件を満たすために、必要に応じてソフト改行を追加できます。ソフト改行は、エンコードされた行の末尾にある「=」で構成され、デコードされたテキストで改行を引き起こしません。

4

14 に答える 14

22

フレームワーク ライブラリにはこれを行うための機能がありますが、完全に公開されているようには見えません。実装は内部クラスにありSystem.Net.Mime.QuotedPrintableStreamます。このクラスは、必要な処理を行うメソッドDecodeBytesを定義します。このメソッドは、MIME ヘッダーのデコードに使用される 1 つのメソッドのみで使用されているようです。このメソッドも内部ですが、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);
        }
    }
}

出力を生成します。

ああ、セニョール!

キャリッジリターンなどが正しく処理されることを確認するために、いくつかのテストを行う必要がある場合がありますが、簡単なテストではそうであるように見えました. ただし、ユースケースが MIME ヘッダー文字列のデコードに十分近く、ライブラリに加えられた変更によって壊れるとは思わない場合を除き、この機能に依存するのは賢明ではないかもしれません。独自の quoted-printable デコーダーを作成する方がよい場合があります。

于 2010-02-10T10:55:05.193 に答える
19

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;
}
于 2011-11-29T08:15:56.033 に答える
10

私はこれを急いで書き上げました。

    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", "");
    }       
于 2011-05-10T20:10:11.317 に答える
6

UTF-8 エンコーディングで quoted-printable をデコードする場合、引用された印刷可能な文字が一緒に実行されている場合、他の人が示したように、各 quoted-printable シーケンスを一度に 1 つずつデコードできないことに注意する必要があります。

たとえば、次のシーケンス =E2=80=99 があり、これを UTF8 を使用して一度に 1 つずつデコードすると、3 つの「奇妙な」文字が得られます。代わりに、3 バイトの配列を構築し、3 バイトをUTF8 エンコーディングでは、単一のアフォスロープが得られます。

明らかに、ASCII エンコーディングを使用している場合、一度に 1 つずつ問題はありませんが、デコードが実行されるということは、使用されているテキスト エンコーダーに関係なく、コードが機能することを意味します。

ああ、忘れないでください =3D は特殊なケースで、もう一度持っているものをデコードする必要があることを意味します... それはクレイジーな落とし穴です!

それが役立つことを願っています

于 2011-12-22T09:39:12.740 に答える
5

私は動的な解決策を探していましたが、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());
        }

    }

次に、関数を呼び出すことができます

Decode("=E3=82=AB=E3=82=B9=E3", "utf-8")

これはもともとここで発見されました

于 2016-07-27T19:47:28.500 に答える
2

この Quoted Printable Decoder はうまく機能します。

public static byte[] FromHex(byte[] hexData)
    {
        if (hexData == null)
        {
            throw new ArgumentNullException("hexData");
        }

        if (hexData.Length < 2 || (hexData.Length / (double)2 != Math.Floor(hexData.Length / (double)2)))
        {
            throw new Exception("Illegal hex data, hex data must be in two bytes pairs, for example: 0F,FF,A3,... .");
        }

        MemoryStream retVal = new MemoryStream(hexData.Length / 2);
        // Loop hex value pairs
        for (int i = 0; i < hexData.Length; i += 2)
        {
            byte[] hexPairInDecimal = new byte[2];
            // We need to convert hex char to decimal number, for example F = 15
            for (int h = 0; h < 2; h++)
            {
                if (((char)hexData[i + h]) == '0')
                {
                    hexPairInDecimal[h] = 0;
                }
                else if (((char)hexData[i + h]) == '1')
                {
                    hexPairInDecimal[h] = 1;
                }
                else if (((char)hexData[i + h]) == '2')
                {
                    hexPairInDecimal[h] = 2;
                }
                else if (((char)hexData[i + h]) == '3')
                {
                    hexPairInDecimal[h] = 3;
                }
                else if (((char)hexData[i + h]) == '4')
                {
                    hexPairInDecimal[h] = 4;
                }
                else if (((char)hexData[i + h]) == '5')
                {
                    hexPairInDecimal[h] = 5;
                }
                else if (((char)hexData[i + h]) == '6')
                {
                    hexPairInDecimal[h] = 6;
                }
                else if (((char)hexData[i + h]) == '7')
                {
                    hexPairInDecimal[h] = 7;
                }
                else if (((char)hexData[i + h]) == '8')
                {
                    hexPairInDecimal[h] = 8;
                }
                else if (((char)hexData[i + h]) == '9')
                {
                    hexPairInDecimal[h] = 9;
                }
                else if (((char)hexData[i + h]) == 'A' || ((char)hexData[i + h]) == 'a')
                {
                    hexPairInDecimal[h] = 10;
                }
                else if (((char)hexData[i + h]) == 'B' || ((char)hexData[i + h]) == 'b')
                {
                    hexPairInDecimal[h] = 11;
                }
                else if (((char)hexData[i + h]) == 'C' || ((char)hexData[i + h]) == 'c')
                {
                    hexPairInDecimal[h] = 12;
                }
                else if (((char)hexData[i + h]) == 'D' || ((char)hexData[i + h]) == 'd')
                {
                    hexPairInDecimal[h] = 13;
                }
                else if (((char)hexData[i + h]) == 'E' || ((char)hexData[i + h]) == 'e')
                {
                    hexPairInDecimal[h] = 14;
                }
                else if (((char)hexData[i + h]) == 'F' || ((char)hexData[i + h]) == 'f')
                {
                    hexPairInDecimal[h] = 15;
                }
            }

            // Join hex 4 bit(left hex cahr) + 4bit(right hex char) in bytes 8 it
            retVal.WriteByte((byte)((hexPairInDecimal[0] << 4) | hexPairInDecimal[1]));
        }

        return retVal.ToArray();
    }
    public static byte[] QuotedPrintableDecode(byte[] data)
    {
        if (data == null)
        {
            throw new ArgumentNullException("data");
        }

        MemoryStream msRetVal = new MemoryStream();
        MemoryStream msSourceStream = new MemoryStream(data);

        int b = msSourceStream.ReadByte();
        while (b > -1)
        {
            // Encoded 8-bit byte(=XX) or soft line break(=CRLF)
            if (b == '=')
            {
                byte[] buffer = new byte[2];
                int nCount = msSourceStream.Read(buffer, 0, 2);
                if (nCount == 2)
                {
                    // Soft line break, line splitted, just skip CRLF
                    if (buffer[0] == '\r' && buffer[1] == '\n')
                    {
                    }
                    // This must be encoded 8-bit byte
                    else
                    {
                        try
                        {
                            msRetVal.Write(FromHex(buffer), 0, 1);
                        }
                        catch
                        {
                            // Illegal value after =, just leave it as is
                            msRetVal.WriteByte((byte)'=');
                            msRetVal.Write(buffer, 0, 2);
                        }
                    }
                }
                // Illegal =, just leave as it is
                else
                {
                    msRetVal.Write(buffer, 0, nCount);
                }
            }
            // Just write back all other bytes
            else
            {
                msRetVal.WriteByte((byte)b);
            }

            // Read next byte
            b = msSourceStream.ReadByte();
        }

        return msRetVal.ToArray();
    }
于 2012-02-15T14:21:45.753 に答える
1

より良い解決策

    private static string DecodeQuotedPrintables(string input, string charSet)
    {
        try
        {
            enc = Encoding.GetEncoding(CharSet);
        }
        catch
        {
            enc = new UTF8Encoding();
        }

        var occurences = new Regex(@"(=[0-9A-Z]{2}){1,}", RegexOptions.Multiline);
        var matches = occurences.Matches(input);

    foreach (Match match in matches)
    {
            try
            {
                byte[] b = new byte[match.Groups[0].Value.Length / 3];
                for (int i = 0; i < match.Groups[0].Value.Length / 3; i++)
                {
                    b[i] = byte.Parse(match.Groups[0].Value.Substring(i * 3 + 1, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
                }
                char[] hexChar = enc.GetChars(b);
                input = input.Replace(match.Groups[0].Value, hexChar[0].ToString());
        }
            catch
            { ;}
        }
        input = input.Replace("=\r\n", "").Replace("=\n", "").Replace("?=", "");

        return input;
}
于 2012-02-01T10:18:17.933 に答える
1

私のために働いた唯一のもの。

http://sourceforge.net/apps/trac/syncmldotnet/wiki/Quoted%20Printable

QP をデコードする必要があるだけの場合は、上記のリンクからコード内の 3 つの関数を取得します。

    HexDecoderEvaluator(Match m)
    HexDecoder(string line)
    Decode(string encodedText)

そして、ちょうど:

var humanReadable = Decode(myQPString);

楽しみ

于 2013-09-17T06:32:27.727 に答える
0

Martin Murphy の (動作しない) コードの少し改良されたバージョン:

static Regex reQuotHex = new Regex(@"=[0-9A-H]{2}", RegexOptions.Multiline|RegexOptions.Compiled);

public static string DecodeQuotedPrintable(string input)
{
    var dic = new Dictionary<string, string>();
    foreach (var qp in new HashSet<string>(reQuotHex.Matches(input).Cast<Match>().Select(m => m.Value)))
        dic[qp] = ((char)Convert.ToInt32(qp.Substring(1), 16)).ToString();
        
    foreach (string qp in dic.Keys) {
        input = input.Replace(qp, dic[qp]);
    }
    return input.Replace("=\r\n", "");
}
于 2021-05-01T01:02:45.617 に答える
-1
public static string DecodeQuotedPrintables(string input, Encoding encoding)
    {
        var regex = new Regex(@"\=(?<Symbol>[0-9A-Z]{2})", RegexOptions.Multiline);
        var matches = regex.Matches(input);
        var bytes = new byte[matches.Count];

        for (var i = 0; i < matches.Count; i++)
        {
            bytes[i] = Convert.ToByte(matches[i].Groups["Symbol"].Value, 16);
        }

        return encoding.GetString(bytes);
    }
于 2014-04-09T06:44:24.097 に答える