【问题标题】:Algorithm for re-wrapping hard-wrapped text?重新包装硬包装文本的算法?
【发布时间】:2008-12-30 14:18:32
【问题描述】:

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

这是来自 Contoso 客户服务的消息。 最近,您请求客户支持。以下是您的摘要 请求和我们的答复。 -------------------------------------------------- ------------------ Contoso (Fred) 于 2008 年 12 月 30 日星期二上午 9:04 -------------------------------------------------- ------------------ 约翰: 我已经修改了你的地址。您可以通过登录来确认我的工作 我们网站上的“您的帐户”。您的订单应该今天发货。 感谢您在 Contoso 购物。 -------------------------------------------------- ------------------ 您于 2008 年 12 月 30 日星期二上午 8:03 -------------------------------------------------- ------------------ 糟糕,我输入了错误的地址。你能把它改成 弗雷德·史密斯 主街 123 号 弗吉尼亚州任何镇 12345 谢谢! -- 弗雷德·史密斯 Contoso 产品爱好者

一般来说,这一切都很好,但有一个领域我现在有点推迟清理,它处理文本换行。为了生成像上面这样漂亮的电子邮件格式,我需要重新包装客户最初发送的文本。

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

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

糟糕,我输入了错误的地址。你能把它改成 弗雷德·史密斯 123 Main St Anytown, VA 12345 谢谢! -- Fred Smith Contoso 产品爱好者

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

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

谢谢。

【问题讨论】:

    标签: algorithm text string word-wrap


    【解决方案1】:

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

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

    【讨论】:

    • 感谢这个简单的想法。请参阅下面的答案以获取快速而简单的示例实现。
    【解决方案2】:

    我有两个建议,如下。

    • 注意标点符号:这将帮助您区分“硬换行”换行符和“段落结尾”换行符(因为,如果行以句号结尾,则更有可能用户希望它成为段落的结尾。

    • 1234563长字符;因为 30 远小于 79,所以您知道地址行是由用户而不是由用户的文本换行算法破坏的。

    另外,请注意缩进:从左侧缩进空格的行可能被认为是新段落,与之前的行分开,就像在这个论坛上一样。

    【讨论】:

      【解决方案3】:

      按照上面 Ole 的建议,我重新设计了实现以查看阈值。它似乎可以很好地处理我抛出的大多数场景,而无需我发疯并编写真正理解英语的代码。

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

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

      这里有一些代码,我的几个小时前的实现,可能仍然在一些边缘情况下隐藏(使用 C#)。它比我以前的解决方案要简单得多,这很好。

      Source Code

      下面是一些执行该代码的单元测试(使用 MSTest):

      Test Code

      如果有人有更好的实现(毫无疑问存在更好的实现),我很乐意阅读您的想法!谢谢。

      【讨论】:

        猜你喜欢
        • 2010-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-18
        • 2011-11-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多