it-swarm.com.de

C #: Klasse zum Dekodieren Quoted-Printable-Kodierung?

Gibt es eine vorhandene Klasse in C #, die Quoted-Printable - Codierungen in String konvertieren kann? Klicken Sie auf den obigen Link, um weitere Informationen zur Kodierung zu erhalten.

Das Folgende wird aus dem obigen Link für Ihre Bequemlichkeit zitiert.

Jeder 8-Bit-Bytewert kann mit 3 Zeichen codiert werden, wobei ein "=" gefolgt von zwei hexadezimalen Ziffern (0–9 oder AF) den numerischen Wert des Bytes darstellt. Beispielsweise kann ein US-ASCII-Form-Feed-Zeichen (Dezimalwert 12) durch "= 0C" und ein US-ASCII-Gleichheitszeichen (Dezimalwert 61) durch "= 3D" dargestellt werden. Alle Zeichen außer druckbaren ASCII Zeichen oder Zeilenendezeichen müssen auf diese Weise codiert werden.

Alle druckbaren ASCII Zeichen (Dezimalwerte zwischen 33 und 126) können einzeln dargestellt werden, mit Ausnahme von "=" (Dezimal 61).

ASCII-Tabulator- und Leerzeichen, Dezimalwerte 9 und 32, können einzeln dargestellt werden, es sei denn, diese Zeichen stehen am Ende einer Zeile. Wenn eines dieser Zeichen am Ende einer Zeile steht, muss es als "= 09" (Tabulator) oder "= 20" (Leerzeichen) codiert werden.

Wenn die zu codierenden Daten sinnvolle Zeilenumbrüche enthalten, müssen sie als ASCII CR LF Sequenz codiert werden, nicht als ihre ursprünglichen Bytewerte. Umgekehrt, wenn die Bytewerte 13 und 10 andere Bedeutungen als das Zeilenende haben, müssen sie als = 0D und = 0A codiert werden.

Zeilen mit in Anführungszeichen gesetzten druckbaren codierten Daten dürfen nicht länger als 76 Zeichen sein. Um diese Anforderung zu erfüllen, ohne den codierten Text zu ändern, können nach Wunsch weiche Zeilenumbrüche hinzugefügt werden. Ein weicher Zeilenumbruch besteht aus einem "=" am Ende einer codierten Zeile und verursacht keinen Zeilenumbruch im decodierten Text.

25
Lopper

Es gibt Funktionen in den Framework-Bibliotheken, um dies zu tun, aber es scheint nicht sauber verfügbar zu sein. Die Implementierung erfolgt in der internen Klasse System.Net.Mime.QuotedPrintableStream. Diese Klasse definiert eine Methode namens DecodeBytes, die das tut, was Sie wollen. Die Methode scheint nur von einer Methode verwendet zu werden, die zum Dekodieren von MIME-Headern verwendet wird. Diese Methode ist ebenfalls intern, wird jedoch an einigen Stellen ziemlich direkt aufgerufen, z. B. beim Attachment.Name setter. Eine Demonstration:

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);
        }
    }
}

Erzeugt die Ausgabe:

¡Hola, _señor!

Möglicherweise müssen Sie einige Tests durchführen, um sicherzustellen, dass die Rücksendungen usw. korrekt behandelt werden, obwohl ich in einem kurzen Test den Eindruck hatte, dass dies der Fall war. Es ist jedoch möglicherweise nicht ratsam, sich auf diese Funktionalität zu verlassen, es sei denn, Ihr Anwendungsfall ist nahe genug, um eine MIME-Header-Zeichenfolge zu dekodieren, von der Sie nicht glauben, dass sie durch Änderungen an der Bibliothek beschädigt wird. Vielleicht ist es besser, einen eigenen Decoder zu schreiben, der mit einem Zitat gedruckt werden kann.

19
Dave

Ich habe die Lösung von Martin Murphy erweitert und hoffe, dass sie in jedem Fall funktioniert.

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;
}
16
Igor Semkiv

Ich habe das ganz schnell geschrieben.

    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", "");
    }       
7
Martin Murphy

Wenn Sie Quoted-Printable mit UTF-8-Codierung decodieren, müssen Sie wissen, dass Sie nicht jede Quoted-Printable-Sequenz einzeln decodieren können, wie die anderen gezeigt haben, wenn mehrere Quoted-Printable-Zeichen gleichzeitig vorhanden sind.

Zum Beispiel - wenn Sie die folgende Sequenz haben = E2 = 80 = 99 und diese mit UTF8 einzeln dekodieren, erhalten Sie drei "seltsame" Zeichen - wenn Sie stattdessen ein Array von drei Bytes erstellen und die drei Bytes mit konvertieren Mit der UTF8-Codierung erhalten Sie ein einzelnes Aphostrop.

Wenn Sie die ASCII - Kodierung verwenden, ist die Einzelkodierung natürlich kein Problem. Die Dekodierung bedeutet jedoch, dass Ihr Code unabhängig vom verwendeten Textkodierer funktioniert.

Oh und nicht vergessen = 3D ist ein Sonderfall, der bedeutet, dass Sie dekodieren müssen, was auch immer Sie noch haben ... Das ist eine verrückte Geschichte!

Hoffentlich hilft das

4
Demented Devil
    private string quotedprintable(string data, string encoding)
    {
        data = data.Replace("=\r\n", "");
        for (int position = -1; (position = data.IndexOf("=", position + 1)) != -1;)
        {
            string leftpart = data.Substring(0, position);
            System.Collections.ArrayList hex = new System.Collections.ArrayList();
            hex.Add(data.Substring(1 + position, 2));
            while (position + 3 < data.Length && data.Substring(position + 3, 1) == "=")
            {
                position = position + 3;
                hex.Add(data.Substring(1 + position, 2));
            }
            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);
            string rightpart = data.Substring(position + 3);
            data = leftpart + equivalent + rightpart;
        }
        return data;
    }
2
iaceian

Dieser zitierte druckbare Decoder funktioniert hervorragend!

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();
    }
2

Ich war auf der Suche nach einer dynamischen Lösung und habe 2 Tage lang verschiedene Lösungen ausprobiert. Diese Lösung unterstützt japanische Zeichen und andere Standardzeichensätze

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());
        }

    }

Dann können Sie die Funktion mit aufrufen

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

Dies wurde ursprünglich gefunden hier

2
Lee Harris

Der einzige, der für mich gearbeitet hat.

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

Wenn Sie nur die QPs dekodieren müssen, ziehen Sie diese drei Funktionen aus dem obigen Link in Ihren Code:

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

Und dann einfach:

var humanReadable = Decode(myQPString);

Genießen

1
Pizzaboy

Bessere Lösung

    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;
}
1
Igor Semkiv
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);
    }
0
Kachalov Sergey

Manchmal besteht die Zeichenfolge in einer EML-Datei aus mehreren codierten Teilen. Dies ist eine Funktion, um die Dave-Methode für folgende Fälle zu verwenden:

public string DecodeQP(string codedstring)
{
    Regex codified;

    codified=new Regex(@"=\?((?!\?=).)*\?=", RegexOptions.IgnoreCase);
    MatchCollection setMatches = codified.Matches(cadena);
    if(setMatches.Count > 0)
    {
        Attachment attdecode;
        codedstring= "";
        foreach (Match match in setMatches)
        {
            attdecode = Attachment.CreateAttachmentFromString("", match.Value);
            codedstring+= attdecode.Name;

        }                
    }
    return codedstring;
}
0
Armando Saenz

Bitte beachten Sie: Lösungen mit "input.Replace" sind im gesamten Internet verfügbar und dennoch nicht korrekt.

Sehen Sie, wenn Sie EIN decodiertes Symbol haben und dann "replace" ,VERWENDEN, WERDEN ALLESymbole in "input" ersetzt und alle folgenden Decodierungen werden abgebrochen.

Richtigere Lösung:

public static string DecodeQuotedPrintable(string input, string charSet)
    {

        Encoding enc;

        try
        {
            enc = Encoding.GetEncoding(charSet);
        }
        catch
        {
            enc = new UTF8Encoding();
        }

        input = input.Replace("=\r\n=", "=");
        input = input.Replace("=\r\n ", "\r\n ");
        input = input.Replace("= \r\n", " \r\n");
        var occurences = new Regex(@"(=[0-9A-Z]{2})", RegexOptions.Multiline); //{1,}
        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, new String(hexChar));

            }
            catch
            { Console.WriteLine("QP dec err"); }
        }
        input = input.Replace("?=", ""); //.Replace("\r\n", "");

        return input;
    }
0
Don Joe