最快的SMTP发送行尾修复方法是什么?
我正在编写一个电子邮件应用程序,用来生成通过SMTP发送的邮件。这意味着我需要把所有单独的\n和\r字符转换成大家熟悉的\r\n格式。
CRLF = '\r\n'
msg = re.sub(r'(?<!\r)\n', CRLF, msg)
msg = re.sub(r'\r(?!\n)', CRLF, msg)
问题是,这个过程速度不太快。在处理大约80千字节的邮件时,这个转换过程几乎占用了发送邮件时间的30%!
你能做得更好吗?我期待你们用Python的高超技巧来解决这个问题。
5 个回答
在你写字符串的时候,直接把它们替换掉,这样就能省事。如果你用正则表达式或者其他方法,就得分两步走:第一步替换字符,第二步再写入。这时候,创建一个新的流类,把它包裹在你要写入的地方是个不错的办法;我们在System.Net.Mail中就是这么做的,这样我就可以用同一个流编码器同时写入文件和网络流。不过,要想给你一个更好的建议,我需要看看你的代码。另外,记住实际的替换速度不会变快,但总的执行时间会减少,因为你只需要走一遍,而不是两遍(前提是你确实把邮件的输出写到某个地方)。
可能是因为在字符串中间插入一个额外的字符导致了问题。
当你要替换文本“hello \r world”时,实际上需要把整个字符串的大小增加一个字符,变成“hello \r\n world”。
我建议你可以遍历这个字符串,逐个查看字符。如果不是 \r 或 \n,就把它添加到新的字符串中。如果是 \r 或 \n,就用正确的值来更新新的字符串。
下面是用C#写的代码(转换成Python应该很简单)。
string FixLineEndings(string input)
{
if (string.IsNullOrEmpty(input))
return string.Empty;
StringBuilder rv = new StringBuilder(input.Length);
for(int i = 0; i < input.Length; i++)
{
char c = input[i];
if (c != '\r' && c != '\n')
{
rv.Append(c);
}
else if (c == '\n')
{
rv.Append("\r\n");
}
else if (c == '\r')
{
if (i == input.Length - 1)
{
rv.Append("\r\n"); //a \r at the end of the string
}
else if (input[i + 1] != '\n')
{
rv.Append("\r\n");
}
}
}
return rv.ToString();
}
这个问题让我觉得很有趣,于是我写了一个示例程序来测试。我使用了另一个答案中给出的正则表达式,使用正则表达式的代码是:
static readonly Regex _r1 = new Regex(@"(?
我尝试了很多测试案例,输出结果是:
------------------------ Size: 1000 characters All\r String: 00:00:00.0038237 Regex : 00:00:00.0047669 All\r\n String: 00:00:00.0001745 Regex : 00:00:00.0009238 All\n String: 00:00:00.0024014 Regex : 00:00:00.0029281 No \r or \n String: 00:00:00.0000904 Regex : 00:00:00.0000628 \r at every 100th position and \n at every 102th position String: 00:00:00.0002232 Regex : 00:00:00.0001937 ------------------------ Size: 10000 characters All\r String: 00:00:00.0010271 Regex : 00:00:00.0096480 All\r\n String: 00:00:00.0006441 Regex : 00:00:00.0038943 All\n String: 00:00:00.0010618 Regex : 00:00:00.0136604 No \r or \n String: 00:00:00.0006781 Regex : 00:00:00.0001943 \r at every 100th position and \n at every 102th position String: 00:00:00.0006537 Regex : 00:00:00.0005838
这些结果显示,在 \r 和 \n 的数量较多的情况下,字符串替换功能表现得更好。不过在一般情况下,原来的正则表达式方法要快得多(看看最后一组测试案例——那些没有 \r\n 且只有少量 \r 和 \n 的情况)。
当然,这段代码是用C#写的,而不是Python,但我猜在不同语言之间运行时间会有相似之处。
这个正则表达式帮了我:
re.sub(r'\r\n|\r|\n', '\r\n', msg)
但最后这个代码更有效:
msg.replace('\r\n','\n').replace('\r','\n').replace('\n','\r\n')
最开始的正则表达式把/usr/share/dict/words里的换行符从\n转换成\r\n花了0.6秒,而新的正则表达式只用了0.3秒,使用replace()方法则只用了0.08秒。