2010-02-09 21 views
24

C#中是否存在可將Quoted-Printable編碼轉換爲String的現有類?點擊上面的鏈接獲取更多關於編碼的信息。C#:用於解碼引用打印編碼的類?

以下是引用以上鍊接爲您提供的便利。

任意8位字節的值可以被編碼 與3個字符,一個「=」隨後 兩個十六進制數字(0-9或A-F) 表示字節的數值。例如,由「= 0C」表示的US-ASCII換頁符 字符(十進制值12)可以是 ,並且由「= 3D」表示的等號(十進制值61)是 。所有字符 (可打印的ASCII字符除外)或 行尾字符必須以此方式編碼爲 。

所有可打印的ASCII字符 (十進制33和126之間的值)可以通過本身除了 「=」 (十進制61)來表示。

ASCII標籤和空格字符, 十進制值9和32,可以由自己 表示,除非這些 字符出現在 的線的端部。如果其中一個字符 出現在行尾,則必須將 編碼爲「= 09」(製表符)或「= 20」 (空格)。

如果正在編碼的數據包含 有意義換行符,它們必須是 編碼爲ASCII CR LF序列, 不是作爲其原始的字節值。相反地​​,如果字節值13和10 的含義不是行尾 那麼它們必須被編碼爲= 0D和 = 0A。

引用打印的編碼數據行 不得超過76個字符。 爲了滿足這個要求,不用 改變編碼的文本,可以根據需要添加軟線 中斷。一個軟 換行符包含編碼行的 末尾的「=」,而不是 導致解碼的 文本中出現換行符。

+0

我剛剛發佈了一個簡單的答案UTF8解碼這裏:http://stackoverflow.com/questions/37540244/how-to-convert-quoted-print-string/37540375 #37540375 – ib11

回答

19

框架庫中有功能可以完成此操作,但它似乎並沒有完全公開。該實現位於內部類System.Net.Mime.QuotedPrintableStream中。這個類定義了一個叫做DecodeBytes的方法,它可以做你想做的事。該方法似乎僅用於解碼MIME頭的一種方法。這種方法也是內部的,但是可以直接在幾個地方調用,例如Attachment.Name setter。演示:

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頭部字符串,而您認爲這不會因爲對該庫所做的任何更改而被破壞。編寫自己的引用可打印解碼器可能會更好。

+0

這正是我正在尋找的。謝謝戴夫! :) – Lopper

+6

這不會轉換= 3D等我和代碼項目版本解碼失敗。 –

+1

框架2中存在錯誤,它不能處理編碼字符串中的下劃線。下劃線代表舊分析的空間。它在版本4中得到了修復。這種方式有另一個小問題,如果字符集信息不在字符串的開頭,它就不能對其進行解碼。這樣的編碼字符串** ID:12345Arpège** –

5

我寫得很快。

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

我擴展了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; 
     } 
+2

非常感謝你們......它解決了我的問題,這就是我正在尋找的許多小時。 –

+0

輝煌 - 謝謝 – Ashby

+2

不支持=和回車在這一行''如果你相信真相= 3Dbeauty ,那麼肯定= \ n數學是哲學中最美麗的分支。「' –

4

如果你是解碼引用可打印使用UTF-8編碼,你需要知道,如果有運行,你不能解碼每個引用可打印序列中的一個-AT-A-時間作爲其他人已經表明一起引用可打印的字符。例如 - 如果您有以下序列= E2 = 80 = 99,並且使用UTF8一次解碼,則會得到三個「奇怪」字符 - 如果您改爲創建一個由三個字節組成的數組並將其轉換用UTF8編碼的三個字節得到一個單一的aphostrope。

顯然,如果您使用的是ASCII編碼,那麼一次只能一個一個都沒有問題,但解碼運行意味着您的代碼無論使用何種文本編碼器都能正常工作。

哦,別忘了= 3D是一種特殊情況,意味着你需要解碼任何你有更多的時間......這是一個瘋狂的陷阱!

希望幫助

+1

是的,這更接近[Skeet的回答在這裏](http ://stackoverflow.com/a/3289987/1028230)。我們應該將引用的Printable看作字符,而不是將字節序列化。首先解碼爲字節,然後將該字節數組解碼爲您的編碼的字符串 - 「System.Text.Encoding.UTF8.GetString(byteArray)」或您有什麼。試圖從小於128的字節「補救」字符是一個頭痛的錯誤。 – ruffin

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

此引用Printable解碼器的偉大工程!

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

沒有字符集支持 –

+0

偉大的解決方案,像一個魅力工作。 – Barun

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

嘗試解釋你的解決方案。你可以通過編輯你的答案來完成。 – juanreyesv

+0

這個功能如何解決這個問題。請解釋。 – Narendra

2
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; 
    } 
+0

this.Text = quotedprintable(「= 3D」,「utf-8」); – iaceian

+0

這支持順序十六進制組合爲字節,然後轉換爲編碼 – iaceian

+0

適用於多個連續的多字節字符。優秀! – jk7

1

我正在尋找一個動態解決方案,並花了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") 

功能這是最初發現here

0

有時候串入一個EML文件由由幾個編碼部分。這是使用Dave的方法,對於這些情況的功能:

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

請注意: 解決方案「input.Replace」遍佈互聯網,他們仍然是不正確的。

看,如果你有一個解碼後的符號,然後使用「替換」在「輸入」 ALL符號將被替換,然後所有後續的解碼將被打破。

更正確的解決辦法:

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

另外一個有趣的事實是: 如果它是unicode,它可以只是一個符號或一組符號匹配一個符號。例如= E2 = 80 = 99和= E2 = 80 = 99。 總之,這個解決方案根本不起作用。 –