C #: Klasse für die Decodierung Quoted-Printable-Kodierung?
-
19-09-2019 - |
Frage
Gibt es eine vorhandene Klasse in C #, die Quoted-Printable Codierung umwandeln kann String
? Klicken Sie auf den Link oben, um mehr Informationen über die Codierung zu erhalten.
Das folgende ist aus dem obigen Link für Ihre Bequemlichkeit angegeben.
Jede 8-Bit-Byte-Wert codiert werden mit 3 Zeichen ein „=“, gefolgt von zwei Hexadezimalziffern (0-9 oder A-F) repräsentiert den numerischen Wert des Byte. Zum Beispiel kann ein Feed US-ASCII-Form Zeichen (Dezimalwert 12) sein kann, durch "= 0C" repräsentiert, und einem US-ASCII Gleichheitszeichen (Dezimalwert 61) durch "= 3D" dargestellt. Alle Zeichen außer druckbaren ASCII-Zeichen oder Zeilenende-Zeichen muß codiert werden, auf diese Weise.
Alle druckbaren ASCII-Zeichen (Dezimalwerte zwischen 33 und 126) kann selbst dargestellt werden, Ausnahme "=" (dezimal 61).
ASCII Tabulatoren und Leerzeichen, Dezimalwerten 9 und 32, kann sein selbst vertreten, es sei denn, diese Zeichen erscheinen am Ende eine Linie. Wenn eines dieser Zeichen erscheint am Ende einer Zeile für muss codiert werden als "= 09" (TAB) oder "= 20" (Raum).
Wenn die Daten codiert werden, enthält sinnvolle Zeilenumbrüche müssen sie sein codiert als ASCII-CR LF-Sequenz, nicht als ihre ursprünglichen Byte-Werte. Umgekehrt, wenn Byte-Werte 13 und 10 haben andere Bedeutungen als Zeilenende dann müssen sie als = 0D codiert werden und = 0A.
Die Linien von quoted-printable kodierten Daten darf nicht als 76 Zeichen lang sein. Zur Erfüllung dieser Anforderung ohne Ändern der codierten Text, weiche Linie Brüche können wie gewünscht zugegeben werden. Ein weiches Leitungsbruch besteht aus einem „=“ in der Das Ende einer Leitung codierten und nicht veranlassen, einen Zeilenumbruch in dem decodierten Text.
Lösung
Es gibt Funktionen in dem Rahmen Bibliotheken, dies zu tun, aber es scheint nicht sauber ausgesetzt werden. Die Umsetzung ist in der internen Klasse System.Net.Mime.QuotedPrintableStream
. Diese Klasse definiert eine Methode namens DecodeBytes
die das tut, was Sie wollen. Das Verfahren wird durch nur ein Verfahren verwendet werden, das verwendet wird, MIME-Header zu dekodieren. Dieses Verfahren ist auch intern, ist aber ziemlich direkt in ein paar Orten, zum Beispiel genannt, der 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!
Sie haben einige Tests zu tun Wagenrücklauf zu gewährleisten, wird usw. behandelt korrekt, obwohl in einem Schnelltest Ich habe sie zu sein scheint. Es kann aber nicht klug sein, auf diese Funktion verlassen, es sei denn, Ihr Anwendungsfall nahe genug, um die Decodierung eines MIME-Header-Zeichenfolge, die Sie nicht denken, wird es durch Änderungen an der Bibliothek gemacht gebrochen werden. Vielleicht haben Sie besser Ihre eigenen quoted-printable Decoder zu schreiben.
Andere Tipps
I erweitert die Lösung von Martin Murphy und ich hoffe, dass es in jedem Fall funktionieren wird.
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;
}
Ich schrieb diese bis ganz schnell.
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", "");
}
Wenn Sie Decodierung quoted-printable mit UTF-8-Codierung Sie sich bewusst sein müssen, dass Sie nicht jede quoted-printable Sequenz dekodieren kann man-at-a-time als die anderen haben gezeigt, wenn es läuft von quoted-printable Zeichen zusammen.
Zum Beispiel - wenn Sie die folgende Sequenz = E2 = 80 = 99 und dekodieren diese unter Verwendung von UTF8 one-at-a-time Sie drei „weird“ Zeichen bekommen - wenn Sie stattdessen eine Reihe von drei Bytes bauen und wandeln die drei Bytes mit der UTF8-Codierung Sie eine einzelne aphostrope erhalten.
Natürlich, wenn Sie ASCII-Codierung verwenden, dann einer-at-a-time ist jedoch kein Problem, läuft Decodierung bedeutet, dass Ihr Code unabhängig von dem Text-Encoder verwendet, funktionieren wird.
Oh, und vergessen Sie nicht, = 3D ist ein Sonderfall, der bedeutet, dass Sie entschlüsseln müssen, was Sie haben ein weiteres Mal ... Das ist eine verrückte Gotcha!
Ich hoffe, das hilft
Dieses Zitat Druck Decoder funktioniert super!
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;
}
Ich war auf der Suche nach einer dynamischen Lösung und verbrachten 2 Tage verschiedene Lösungen versucht. Diese Lösung wird japanische Schriftzeichen und andere Standard-Zeichensä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 aufrufen mit
Decode("=E3=82=AB=E3=82=B9=E3", "utf-8")
Dies war ursprünglich gefunden hier
Die einzige, die für mich gearbeitet.
http://sourceforge.net/apps/trac/syncmldotnet/wiki/ zitiert% 20Printable
Wenn Sie nur die QPs entschlüsseln müssen, ziehen Sie innerhalb des Codes dieser drei Funktionen aus dem obigen Link:
HexDecoderEvaluator(Match m)
HexDecoder(string line)
Decode(string encodedText)
Und dann nur:
var humanReadable = Decode(myQPString);
Genießen
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;
}
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);
}
Manchmal ist die Zeichenfolge in eine EML-Datei wird von mehreren codierten Teilen zusammengesetzt. Dies ist eine Funktion des Dave-Methode für diese 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;
}
Bitte beachten Sie: Lösungen mit „input.Replace“ sind alle über das Internet und sie sind immer noch nicht korrekt.
Sehen Sie, wenn Sie auf ONE decodierte Symbol und verwenden dann "ersetzen" , Alle Symbole in „Eingang“ ersetzt werden, und dann werden alle folgenden Decodierung gebrochen wird.
Weitere richtige 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;
}