Подтвердить что ты не робот

С#: класс для декодирования кодировки с кодовым кодированием?

Существует ли существующий класс на С#, который может конвертировать Quoted-Printable в код String? Нажмите на ссылку выше, чтобы получить дополнительную информацию о кодировке.

Для удобства вам приведена ссылка на приведенную выше ссылку.

Любое значение в 8 бит может быть закодировано с 3 символами, "=" , за которым следует две шестнадцатеричные цифры (0-9 или A-F) представляющий числовое значение байта. Например, канал формы US-ASCII символ (десятичное значение 12) может быть представленный "= 0C", и US-ASCII знак равенства (десятичное значение 61) представленный "= 3D". Все персонажи кроме печатных символов ASCII или символы конца строки должны быть закодированы таким образом.

Все печатные символы ASCII (десятичные значения от 33 до 126) могут быть представлены сами по себе, кроме "=" (десятичная цифра 61).

Вкладка ASCII и пробельные символы, десятичные значения 9 и 32, могут быть представленные сами по себе, за исключением случаев, когда эти символы появляются в конце линии. Если один из этих символов появляется в конце строки, она должна кодироваться как "= 09" (вкладка) или "= 20", (Пробел).

Если кодируемые данные содержат значимые разрывы строк, они должны быть кодируется как последовательность ASCII CR LF, а не как их исходные значения байтов. И наоборот, если значения байтов 13 и 10 имеют значения, отличные от конца строки то они должны быть закодированы как = 0D и = 0A.

Линии кодированных данных с кавычками не должно превышать 76 символов. Чтобы удовлетворить это требование без изменение кодированного текста, мягкая линия разрывы могут быть добавлены по желанию. Мягкий Разрыв строки состоит из "=" на конец закодированной строки и не вызвать разрыв строки в декодированном текст.

4b9b3361

Ответ 1

В библиотеках фреймворков есть функциональность, но это, как представляется, не подвергается чистоте. Реализация выполняется во внутреннем классе System.Net.Mime.QuotedPrintableStream. Этот класс определяет метод DecodeBytes, который делает то, что вы хотите. Метод, по-видимому, используется только одним методом, который используется для декодирования заголовков MIME. Этот метод также является внутренним, но называется довольно прямо в нескольких местах, например, установщиком Attachment.Name. Демонстрация:

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

Производит вывод:

¡Hola, _señor!

Возможно, вам придется провести некоторое тестирование, чтобы обеспечить возврат каретки и т.д., но в кратчайшие сроки я, похоже, это так. Тем не менее, может быть нецелесообразно полагаться на эту функциональность, если ваш прецедент не достаточно близко к расшифровке строки заголовка MIME, которая, по вашему мнению, не будет нарушена никакими изменениями, внесенными в библиотеку. Возможно, вам лучше написать свой собственный декодер с кавычками.

Ответ 2

Я расширил решение 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;
        }

Ответ 3

Я написал это очень быстро.

    public static string DecodeQuotedPrintables(string input)
    {
        var occurences = new Regex(@"=[0-9A-H]{2}", RegexOptions.Multiline);
        var matches = occurences.Matches(input);
        foreach (Match match in matches)
        {
            char hexChar= (char) Convert.ToInt32(match.Groups[0].Value.Substring(1), 16);
            input =input.Replace(match.Groups[0].Value, hexChar.ToString());
        }
        return input.Replace("=\r\n", "");
    }       

Ответ 4

Если вы декодируете кавычки с печатью с кодировкой UTF-8, вам нужно знать, что вы не можете декодировать каждую строку с кавычками для печати один раз в то время, как показали другие, если есть пробежки с цитируемыми печатными символами вместе.

Например, если у вас есть следующая последовательность = E2 = 80 = 99 и декодировать это, используя UTF8 один раз, вы получаете три "странных" символа - если вы вместо этого создадите массив из трех байтов и преобразуете три байта с кодировкой UTF8, вы получаете один aphostrope.

Очевидно, что если вы используете ASCII-кодировку, тогда один-на-время не проблема, однако выполнение декодирования означает, что ваш код будет работать независимо от используемого текстового кодировщика.

О, и не забывайте = 3D - это особый случай, который означает, что вам нужно расшифровать все, что у вас есть еще раз... Это сумасшедшая игра!

Надеюсь, что поможет

Ответ 5

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

Ответ 6

Лучшее решение

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

Ответ 7

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

Ответ 8

Единственный, который работал у меня.

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

Если вам просто нужно декодировать QP, потяните внутри своего кода эти три функции из ссылки выше:

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

А потом просто:

var humanReadable = Decode(myQPString);

Enjoy

Ответ 9

Я искал динамическое решение и потратил 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")

Это изначально было найдено здесь

Ответ 10

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

Ответ 11

Иногда строка в файл EML состоит из нескольких закодированных частей. Это функция для использования метода Дэйва для этих случаев:

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