重新包装硬包装文本的算法?

时间:2008-12-30 14:18:33

标签: algorithm text string wrapping word-wrap

假设我为我所工作的公司编写了一个自定义电子邮件管理应用程序。它从公司的支持帐户中读取电子邮件,并将清理后的纯文本版本存储在数据库中,执行其他整洁的操作,例如将其与客户帐户和流程中的订单相关联。当员工回复邮件时,我的程序会生成一封电子邮件,该电子邮件使用格式化的讨论主题版本发送给客户。如果客户响应,则应用程序在主题行中查找唯一编号以读取传入消息,删除先前的讨论,并将其添加为线程中的新项目。例如:

This is a message from Contoso customer service.

Recently, you requested customer support. Below is a summary of your 
request and our reply.

--------------------------------------------------------------------
Contoso (Fred) on Tuesday, December 30, 2008 at 9:04 a.m.
--------------------------------------------------------------------
John:

I've modified your address. You can confirm my work by logging into
"Your Account" on our Web site. Your order should ship out today.

Thanks for shopping at Contoso.

--------------------------------------------------------------------
You on Tuesday, December 30, 2008 at 8:03 a.m.
--------------------------------------------------------------------
Oops, I entered my address incorrectly. Can you change it to

Fred Smith
123 Main St
Anytown, VA 12345

Thanks!

--
Fred Smith
Contoso Product Lover

一般来说,这一切都很有效,但是有一个领域我现在推迟了一段时间的清理工作,它处理文本包装。为了生成如上所述的漂亮的电子邮件格式,我需要重新包装客户最初发送的文本。

我编写了一个执行此操作的算法(虽然查看代码,但我不完全确定它是如何工作的 - 它可以使用一些重构)。 但它无法区分硬包装换行符,“段落末尾”换行符和“语义”换行符。例如,硬包装换行符是电子邮件的换行符客户端插入段落中以包含长行文本,例如,在79列。段落换行符的结尾是用户在段落中的最后一个句子之后添加的行。语义换行符类似于br标记,例如Fred在上面输入的地址。

我的算法只会在连续的两行中看到一个新的段落,因此它会使客户的电子邮件格式化如下:

Oops, I entered my address incorrectly. Can you change it to

Fred Smith 123 Main St Anytown, VA 12345

Thanks!

-- Fred Smith Contoso Product Lover

每当我尝试编写一个可以按照预期重新包装此文本的版本时,我基本上都会碰壁,因为我需要知道文本的语义,“硬包装”换行符和“我的意思就像一个br“ - 类型的换行符,例如在客户的地址中。 (我连续使用两个换行符来确定何时开始一个新段落,这与大多数人似乎实际输入电子邮件的方式一致。)

任何人都有一个可以按预期重新包装文本的算法吗?或者,在权衡任何给定解决方案的复杂性时,这种实现是否“足够好”?

感谢。

3 个答案:

答案 0 :(得分:3)

您可以尝试检查是否已插入换行符以保持行长度低于最大值(也称为硬换行):只需检查文本中最长的行。然后,对于任何给定的行,您将以下行的第一个单词追加到它。如果结果行超过最大长度,则换行可能是一个硬包装。

更简单的是,您可能只会将(maxlength - 15) <= length <= maxlength中的所有中断视为硬包装(15只是一种有根据的猜测)。这肯定会过滤掉地址和东西中的故意中断,并且在此范围内任何错过的中断都不会对结果造成太大影响。

答案 1 :(得分:2)

我有两条建议如下。

  • 注意标点符号:这将帮助您区分“硬包装”换行符和“段落结尾”换行符(因为,如果该行以句号结束,那么它更可能是用户希望它是一个段落结尾。

  • 注意一条线是否比最大线长短得多:在上面的例子中,你可能有79个字符的“硬包裹”文字,而且你的地址线只有30个长字符;因为30远小于79,你知道地址行被用户破坏而不是用户的文本换行算法。

另外,要注意缩进:从左边用空格缩进的行可能应该是新的段落,与之前的行相差无几,就像在这个论坛上一样。

答案 2 :(得分:2)

根据Ole的建议,我重新设计了我的实现以查看阈值。它似乎处理了我投入的大多数情况,而且我不必疯狂地编写实际理解英语的代码。

基本上,我首先扫描输入字符串并在变量inputMaxLineLength中记录最长的行长度。然后当我重新打包时,如果我遇到索引在inputMaxLineLengthinputMaxLineLength的85%之间的换行符,那么我用空格替换该换行符,因为我认为它是一个硬换行换行符 - 除非它紧接着是另一个换行符,因为我认为它只是一个单行段落恰好在该范围内。例如,如果某人输入了一个简短的项目符号列表,就会发生这种情况。

当然不是很完美,但对于我的场景来说“足够好”,考虑到文本通常是以前的电子邮件客户端开头的一半。

这是一些代码,我的几个小时的实现,在一些边缘情况下(使用C#)可能仍然包含在内。它比我以前的解决方案复杂得多,这很好。

Source Code

这是一些运行该代码的单元测试(使用MSTest):

Test Code

如果有人有更好的实施(毫无疑问会有更好的实施),我会很乐意阅读你的想法!感谢。