C#中是否存在可以将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个字符。 无需满足此要求 改变编码文本,软线 可以根据需要添加中断。柔软 换行符包含一个“=” 编码行的结尾,而不是 导致解码中的换行符 文本。
答案 0 :(得分: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头字符串,您认为它不会被对库所做的任何更改破坏。你可能最好不要编写自己的引用可打印解码器。
答案 1 :(得分:17)
我扩展了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 :(得分:7)
我写得很快。
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", "");
}
答案 3 :(得分:4)
如果使用UTF-8编码解码quoted-printable,则需要注意不能一次一个地解码每个引用的可打印序列,因为其他人已经显示是否存在引用的可打印字符的运行在一起。
例如 - 如果您有以下序列= E2 = 80 = 99并使用UTF8一次解码一次,则会得到三个“怪异”字符 - 如果您构建一个包含三个字节的数组并转换使用UTF8编码的三个字节可以获得单个aphostrope。
显然,如果您使用的是ASCII编码,那么一次一个就没有问题,但解码运行意味着无论使用何种文本编码器,您的代码都能正常工作。
哦,别忘了= 3D是一个特殊的情况,这意味着你需要再解码一下你所拥有的东西......这是一个疯狂的陷阱!
希望有所帮助
答案 4 :(得分: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();
}
答案 5 :(得分: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;
}
答案 6 :(得分:2)
我一直在寻找动态解决方案,并花了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
答案 7 :(得分: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;
}
答案 8 :(得分:1)
唯一一个适合我的人。
http://sourceforge.net/apps/trac/syncmldotnet/wiki/Quoted%20Printable
如果您只需要解码QP,请从上面的链接中删除代码中的三个函数:
HexDecoderEvaluator(Match m)
HexDecoder(string line)
Decode(string encodedText)
然后只是:
var humanReadable = Decode(myQPString);
享受
答案 9 :(得分: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);
}
答案 10 :(得分: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;
}
答案 11 :(得分:0)
请注意: 解决方案&#34; input.Replace&#34;他们都在互联网上,但他们仍然不正确。
请参阅,如果您有一个已解码的符号,然后使用&#34;替换&#34; , &strong;&#34;输入&#34;中的所有符号将被替换,然后所有后续解码将被打破。
更正确的解决方案:
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;
}
答案 12 :(得分:0)
我知道它的老问题,但这应该有所帮助
private static string GetPrintableCharacter(char character)
{
switch (character)
{
case '\a':
{
return "\\a";
}
case '\b':
{
return "\\b";
}
case '\t':
{
return "\\t";
}
case '\n':
{
return "\\n";
}
case '\v':
{
return "\\v";
}
case '\f':
{
return "\\f";
}
case '\r':
{
return "\\r";
}
default:
{
if (character == ' ')
{
break;
}
else
{
throw new InvalidArgumentException(Resources.NOTSUPPORTCHAR, new object[] { character });
}
}
}
return "\\x20";
}
public static string GetPrintableText(string text)
{
StringBuilder stringBuilder = new StringBuilder(1024);
if (text == null)
{
return "[~NULL~]";
}
if (text.Length == 0)
{
return "[~EMPTY~]";
}
stringBuilder.Remove(0, stringBuilder.Length);
int num = 0;
for (int i = 0; i < text.Length; i++)
{
if (text[i] == '\a' || text[i] == '\b' || text[i] == '\f' || text[i] == '\v' || text[i] == '\t' || text[i] == '\n' || text[i] == '\r' || text[i] == ' ')
{
num += 3;
}
}
int length = text.Length + num;
if (stringBuilder.Capacity < length)
{
stringBuilder = new StringBuilder(length);
}
string str = text;
for (int j = 0; j < str.Length; j++)
{
char chr = str[j];
if (chr > ' ')
{
stringBuilder.Append(chr);
}
else
{
stringBuilder.Append(StringHelper.GetPrintableCharacter(chr));
}
}
return stringBuilder.ToString();
}
答案 13 :(得分: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", "");
}