如何转换引用打印字符串
Posted
技术标签:
【中文标题】如何转换引用打印字符串【英文标题】:How to convert Quoted-Print String 【发布时间】:2016-09-29 03:27:32 【问题描述】:我正在 .NET 中处理法语字符串 解码邮件正文,我收到“Chasn=C3=A9 sur illet” 我想得到“Chasné sur illet” 而且我在 2 天的网络搜索中找不到任何解决方案。
C# 或 VB.NET 谁能帮帮我?
谢谢
【问题讨论】:
你能在你设置字符串的地方发布你的代码吗? 您好,我的字符串来自 IMAP 服务器 我阅读了消息并使用 IMAP 命令获取消息正文文本:FETCH BODY[TEXT] 它返回给我一个以 Quoted_printable 格式编码的字符串,但我没有'找不到任何想法做转换器 @MarcCollin 请参阅下面的完整代码。 【参考方案1】:这是 UTF8 编码。
使用这篇文章:
http://www.dpit.co.uk/decoding-quoted-printable-email-in-c/
这是代码(如果有帮助别忘了接受答案):
using System;
using System.Text;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
class Program
static void Main(string[] args)
Console.WriteLine(DecodeQuotedPrintable("Chasn=C3=A9 sur illet"));
Console.ReadKey();
static string DecodeQuotedPrintable(string input)
var occurences = new Regex(@"(=[0-9A-Z][0-9A-Z])+", RegexOptions.Multiline);
var matches = occurences.Matches(input);
foreach (Match m in matches)
byte[] bytes = new byte[m.Value.Length / 3];
for (int i = 0; i < bytes.Length; i++)
string hex = m.Value.Substring(i * 3 + 1, 2);
int iHex = Convert.ToInt32(hex, 16);
bytes[i] = Convert.ToByte(iHex);
input = input.Replace(m.Value, Encoding.UTF8.GetString(bytes));
return input.Replace("=rn", "");
【讨论】:
【参考方案2】: static string ConverFromHex(string source)
string target = string.Empty;
int startPos = source.IndexOf('=', 0);
int prevStartPos = 0;
while (startPos >= 0)
// concat with substring from source
target += source.Substring(prevStartPos, startPos - prevStartPos);
// next offset
startPos++;
// update prev pos
prevStartPos = startPos;
// get substring
string hexString = source.Substring(startPos, 2);
// get int equiv
int hexNum = 0;
if (int.TryParse(hexString, System.Globalization.NumberStyles.AllowHexSpecifier, System.Globalization.CultureInfo.InvariantCulture, out hexNum))
// add to target string
target += (char)hexNum;
// add hex length
prevStartPos += 2;
// next occurence
startPos = source.IndexOf('=', startPos);
// add rest of source
target += source.Substring(prevStartPos);
return target;
【讨论】:
这段代码没有正确处理 OP 的字符串,结果是“Chasné sur illet”。您的代码将每个十六进制数字视为一个单独的字符,但“=C3=A9”应该代表单个字符“é”。【参考方案3】:发件人:https://***.com/a/36803911/6403521 我的解决方案:
[TestMethod]
public void TestMethod1()
Assert.AreEqual("La Bouichère", quotedprintable("La Bouich=C3=A8re", "utf-8"));
Assert.AreEqual("Chasné sur illet", quotedprintable("Chasn=C3=A9 sur illet", "utf-8"));
Assert.AreEqual("é è", quotedprintable("=C3=A9 =C3=A8", "utf-8"));
private string quotedprintable(string pStrIn, string encoding)
String strOut = pStrIn.Replace("=\r\n", "");
// Find the first =
int position = strOut.IndexOf("=");
while (position != -1)
// String before the =
string leftpart = strOut.Substring(0, position);
// get the QuotedPrintable String in a ArrayList
System.Collections.ArrayList hex = new System.Collections.ArrayList();
// The first Part
hex.Add(strOut.Substring(1 + position, 2));
// Look for the next parts
while (position + 3 < strOut.Length && strOut.Substring(position + 3, 1) == "=")
position = position + 3;
hex.Add(strOut.Substring(1 + position, 2));
// In the hex Array, we have two items
// Convert using the GetEncoding Function
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);
// Part of the orignal String after the last QP Symbol
string rightpart = strOut.Substring(position + 3);
// Re build the String
strOut = leftpart + equivalent + rightpart;
// find the new QP Position
position = leftpart.Length + equivalent.Length;
if (rightpart.Length == 0)
position = -1;
else
position = strOut.IndexOf("=", position + 1);
return strOut;
【讨论】:
天哪,这太复杂了。你试过我的答案了吗?【参考方案4】:或者最简单的,只需使用我的MimeKit 库中的QuotedPrintableDecoder:
static string DecodeQuotedPrintable (string input, string charset)
var decoder = new QuotedPrintableDecoder ();
var buffer = Encoding.ASCII.GetBytes (input);
var output = new byte[decoder.EstimateOutputLength (buffer.Length)];
int used = decoder.Decode (buffer, 0, buffer.Length, output);
var encoding = Encoding.GetEncoding (charset);
return encoding.GetString (output, 0, used);
请注意,上面的其他答案假设解码的内容是 ASCII 或 UTF-8,但不一定是这种情况。您需要从您正在解码的 MIME 部分的 Content-Type
标头中获取 charset
参数。
当然...如果您不知道如何获取该信息,您可以简单地使用我很棒的 MailKit 库从 IMAP 获取 MIME 部分并让它为您完成所有这些工作。
【讨论】:
MimeKit 看起来不错,但它希望能够加载流对象。我明白为什么总体上会更好,但是如果您现有的代码库无法在文件加载步骤中轻松放入 MimeKit,AFAICT 就没有将它与字符串一起使用的功能。 FWIW,并非所有电子邮件都可以正确转换为 C# 字符串。问题是电子邮件可以有多个文本部分,每个文本部分使用不同的字符集编码,这意味着通过将其转换为字符串,它将被损坏。只是让您长期了解的事情。【参考方案5】:我们在使用这种方法时遇到了问题 - 它非常慢。 以下增强性能A LOT
public static string FromMailTransferEncoding(this string messageText, Encoding enc, string transferEncoding)
if (string.IsNullOrEmpty(transferEncoding))
return messageText;
if ("quoted-printable".Equals(transferEncoding.ToLower()))
StringBuilder sb = new StringBuilder();
string delimitorRegEx = @"=[\r][\n]";
string[] parts = Regex.Split(messageText, delimitorRegEx);
foreach (string part in parts)
string subPart = part;
Regex occurences = new Regex(@"(=[0-9A-Z][0-9A-Z])+", RegexOptions.Multiline);
MatchCollection matches = occurences.Matches(subPart);
foreach (Match m in matches)
byte[] bytes = new byte[m.Value.Length / 3];
for (int i = 0; i < bytes.Length; i++)
string hex = m.Value.Substring(i * 3 + 1, 2);
int iHex = Convert.ToInt32(hex, 16);
bytes[i] = Convert.ToByte(iHex);
subPart = occurences.Replace(subPart, enc.GetString(bytes), 1);
sb.Append(subPart);
return sb.ToString();
return messageText;
【讨论】:
以上是关于如何转换引用打印字符串的主要内容,如果未能解决你的问题,请参考以下文章