Question

Y at-il une classe existante en C # qui peut convertir Quoted-Printable encodage String ? Cliquez sur le lien ci-dessus pour obtenir plus d'informations sur l'encodage.

Ce qui suit est cité à partir du lien ci-dessus pour votre commodité.

  

Toute valeur d'octet de 8 bits peut être codé   avec 3 caractères, un « = » suivi par   deux chiffres hexadécimaux (0-9 ou A-F)   représentant la valeur numérique de l'octet.   Par exemple, une forme US-ASCII alimentation   caractère (valeur décimale 12) peut être   représenté par "= 0C", et US-ASCII   signe égal (valeur décimale 61) est   représenté par "= 3D". tous les caractères   sauf caractères ASCII imprimables ou   caractères de fin de ligne doit être codé   de cette façon.

     

Tous les caractères ASCII imprimables   (valeurs décimales entre 33 et 126)   peut être représenté par eux-mêmes,   à l'exception "=" (code décimal 61).

     

caractères de tabulation ASCII et de l'espace,   les valeurs décimales 9 et 32, peuvent être   représenté par eux-mêmes, sauf si   ces caractères apparaissent à la fin de   une ligne. Si l'un de ces caractères   apparaît à la fin d'une ligne, il faut   coder en tant que "= 09" (tabulation) ou "= 20"   (Espace).

     

Si les données codées contient   significatives sauts de ligne, ils doivent être   codées comme une séquence ASCII CR LF,   non pas comme leurs valeurs d'octets d'origine.   Inversement, si l'octet valeurs 13 et 10   ont des significations autres que l'extrémité de la ligne   alors ils doivent être codés en = 0D et   = 0A.

     

Lignes de données codées imprimable citée   ne doit pas dépasser 76 caractères.   Pour satisfaire à cette exigence sans   modifier le texte codé, ligne souple   pauses peuvent être ajoutés comme on le souhaite. Une douce   saut de ligne se compose d'une « = » au   fin d'une ligne codée, et ne pas   provoquer un saut de ligne dans le décodée   texte.

Était-ce utile?

La solution

Il existe des fonctionnalités dans les bibliothèques cadres pour ce faire, mais il ne semble pas être proprement exposé. La mise en œuvre est dans le System.Net.Mime.QuotedPrintableStream de classe interne. Cette classe définit une méthode appelée DecodeBytes qui fait ce que vous voulez. La méthode semble être utilisée par une seule méthode qui est utilisée pour décoder les en-têtes MIME. Cette méthode est également interne, mais est appelé assez directement dans deux ou trois endroits, par exemple, le poseur de Attachment.Name. Une démonstration:

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

Produit la sortie:

  

¡Hola, _señor!

Vous pourriez avoir à faire des tests pour assurer des retours chariot, etc sont traités correctement, bien que dans un test rapide, je l'ai fait, ils semblent être. Cependant, il ne peut pas être sage de compter sur cette fonctionnalité à moins que votre cas d'utilisation est assez proche de décodage d'une chaîne d'en-tête MIME que vous ne pensez pas qu'il sera brisé par toutes les modifications apportées à la bibliothèque. Vous pourriez être mieux écrire votre propre décodeur cité imprimable.

Autres conseils

Je tendis la solution de Martin Murphy et j'espère que cela fonctionnera dans tous les cas.

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

J'ai écrit ce jusqu'à très rapide.

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

Si vous décodage cité imprimable avec UTF-8 d'encodage que vous devez être conscient que vous ne pouvez pas décoder chaque séquence cité imprimable une par un temps que les autres ont montré s'il y a des séries de caractères imprimables cités ensemble.

Par exemple - si vous avez la séquence suivante = E2 = 80 = 99 et décoder en utilisant UTF8 un à-un-temps, vous obtenez trois caractères « bizarres » - si vous construisez place un tableau de trois octets et convertir la trois octets avec l'UTF8 vous obtenez un aphostrope.

Il est évident que si vous utilisez le codage ASCII puis un à-un-temps est pas un problème de décodage mais fonctionne signifie que votre code ne fonctionnera indépendamment du codeur de texte utilisé.

Oh, et ne pas oublier = 3D est un cas particulier qui signifie que vous devez décoder ce que vous avez une fois de plus ... C'est un Gotcha fou!

L'espoir qui aide

Ce décodeur imprimable Quoted fonctionne très bien!

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

Je cherchais une solution dynamique et passé 2 jours à essayer différentes solutions. Cette solution soutiendra les caractères japonais et d'autres jeux de caractères standard

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

    }

Ensuite, vous pouvez appeler la fonction avec

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

a été trouvé ici

Le seul qui a fonctionné pour moi.

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

Si vous avez juste besoin de décoder le QP, tirer à l'intérieur de votre code ces trois fonctions à partir du lien ci-dessus:

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

Et puis juste:

var humanReadable = Decode(myQPString);

Profitez

Une meilleure solution

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

Parfois, la chaîne de caractères dans un fichier EML est constitué par plusieurs parties codées. Cette fonction est d'utiliser la méthode de Dave pour ces cas:

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

S'il vous plaît noter: solutions avec « input.Replace » sont sur Internet et encore ils ne sont pas correctes.

Voir, si vous avez un symbole décodé puis utilisez "remplacer" , ALL symboles "entrée" seront remplacés, et tout le décodage suivant sera brisé.

Solution plus correcte:

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;
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top