2008-12-30 9 views
7

Angenommen, ich habe eine benutzerdefinierte E-Mail-Verwaltungsanwendung für das Unternehmen geschrieben, für das ich arbeite. Es liest E-Mails vom Support-Account des Unternehmens und speichert aufgeräumte Textversionen davon in einer Datenbank, wobei andere nette Dinge erledigt werden, wie z. B. die Verknüpfung mit Kundenkonten und Bestellungen. Wenn ein Mitarbeiter auf eine Nachricht antwortet, generiert mein Programm eine E-Mail, die mit einer formatierten Version des Diskussionsthreads an den Kunden gesendet wird. Wenn der Kunde antwortet, sucht die App in der Betreffzeile nach einer eindeutigen Nummer, um die eingehende Nachricht zu lesen, die vorherige Diskussion auszublenden und sie als neues Element im Thread hinzuzufügen. Zum Beispiel:Algorithmus zum Umbruch von hart umschlossenem Text?

 
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 

Im Allgemeinen ist dies alles funktioniert gut, aber es gibt einen Bereich, den ich habe Art setzen für eine Weile Reinigung jetzt, und beschäftigt sich mit Textumbruch. Um das schöne E-Mail-Format wie das obige zu generieren, muss ich den Text, den der Kunde ursprünglich gesendet hat, erneut einpacken.

Ich habe einen Algorithmus geschrieben, der dies tut (obwohl ich mir den Code anschaue, bin ich mir nicht ganz sicher, wie es funktioniert - es könnte etwas Refactoring verwenden). Es kann jedoch nicht zwischen einer Zeilenumbruch-Zeilenumbruchzeile, einer Zeilenumbruch-Zeile und einer semantischen Zeilenumbruch-Zeile unterscheiden. Zum Beispiel ist eine Zeilenumbruch-Zeilenumbruch eine Zeile, die der E-Mail-Client innerhalb eines Absatzes eingefügt hat, um eine lange Textzeile, beispielsweise mit 79 Spalten, zu umbrechen. Ein Ende des Absatzes newline ist einer, den der Benutzer nach dem letzten Satz in einem Absatz hinzugefügt hat. Und eine semantische Newline wäre etwas wie das br-Tag, wie die Adresse, die der Fred oben eingegeben hat.

Mein Algorithmus statt nur einen neuen Absatz als Hinweis auf zwei neue Zeilen in einer Reihe sieht, so dass es die Kunden E-Mail so etwas wie das formatiert werden würde folgende:

 
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 

Jedes Mal, wenn ich versuche, eine Version zu schreiben das würde diesen Text wie beabsichtigt umhüllen, ich traf im Grunde eine Wand, in der ich die Semantik des Textes kennen musste, den Unterschied zwischen einem "Hard-Wrap" Newline und einem "Ich meinte es wirklich wie ein br" -Typ Newline, wie in der Adresse des Kunden. (Ich benutze zwei Zeilenumbrüche hintereinander, um zu bestimmen, wann ein neuer Absatz beginnt, was mit der E-Mail übereinstimmt.)

Jeder hat einen Algorithmus, der den Text als neu einpacken kann beabsichtigt? Oder ist diese Implementierung "gut genug", wenn man die Komplexität einer gegebenen Lösung abwägt?

Danke.

Antwort

3

Sie könnten versuchen, zu überprüfen, ob ein Zeilenumbruch eingefügt wurde, um die Zeilenlänge unter einem Maximum zu halten (auch als "harter Zeilenumbruch" bezeichnet): Überprüfen Sie die längste Zeile im Text. Dann fügst du für jede gegebene Zeile das erste Wort der folgenden Zeile an sie an. Wenn die resultierende Linie die maximale Länge überschreitet, war der Zeilenumbruch wahrscheinlich ein harter Umbruch.

Noch einfacher können Sie nur alle Brüche in (maxlength - 15) <= length <= maxlength als hardwraps betrachten (mit 15 nur eine begründete Schätzung). Dies würde sicherlich vorsätzliche Brüche wie bei Adressen und anderen Dingen herausfiltern, und jede verpasste Pause in diesem Bereich würde das Ergebnis nicht zu stark beeinflussen.

+0

Danke für diese einfache Idee. Siehe meine Antwort unten für eine schnelle und sinnvolle Beispielimplementierung. –

2

Ich habe zwei Vorschläge, wie folgt.

  • Achten Sie auf Zeichensetzung: dies wird Ihnen helfen, zwischen einem „hard-wrap“ Newline und ein „Ende des Absatzes“ Newline zu unterscheiden (weil, wenn die Linie mit einem Punkt endet, dann ist es wahrscheinlicher, dass der Benutzer beabsichtigte, ein Absatzende zu sein.

  • Achten Sie darauf, ob eine Zeile viel kürzer als die maximale Zeilenlänge ist: Im obigen Beispiel könnte Text mit 79 Zeichen "hart umhüllt" sein, plus Adresszeilen mit nur 30 Zeichen lange; Da 30 viel weniger als 79 ist, wissen Sie, dass die Adresszeilen vom Benutzer und nicht vom Text-Wrap-Algorithmus des Benutzers unterbrochen wurden.

Auch, achten Sie auf Einzüge: Linien, die mit Leerzeichen von links eingekerbt sind, kann angenommen werden, neue Absätze zu sein, von den vorhergehenden Linien gebrochen, wie sie auf diesem Forum sind.

2

Nach dem oben genannten Ratschlag von Ole habe ich meine Implementierung überarbeitet, um auf einen Schwellenwert zu schauen. Es scheint, mit den meisten Szenarien fertig zu werden, die ich gut genug darauf einwerfe, ohne dass ich verrückt werden und Code schreiben muss, der die englische Sprache wirklich versteht.

Grundsätzlich scanne ich zuerst die Eingabezeichenfolge und zeichne die längste Zeilenlänge in der Variablen inputMaxLineLength auf. Wenn ich beim Umschreiben eine neue Zeile mit einem Index zwischen inputMaxLineLength und 85% von inputMaxLineLength vorfinde, ersetze ich diese Zeilenumbrüche mit einem Leerzeichen, da es sich um einen neuen Zeilenumbruch handelt - es sei denn, es folgt sofort ein neuer Zeilenumbruch. weil dann nehme ich an, dass es nur ein einzeiliger Absatz ist, der gerade in diesem Bereich passiert. Dies kann zum Beispiel passieren, wenn jemand eine kurze Aufzählung ausgibt.

Sicher nicht perfekt, aber "gut genug" für mein Szenario, wenn man bedenkt, dass der Text von einem früheren E-Mail-Client in der Regel nur halb zerfleischt ist.

Hier ist ein Code, meine einige Stunden alte Implementierung, die wahrscheinlich in einigen Edge-Fällen (unter Verwendung von C#) noch unterläuft. Es ist viel weniger kompliziert als meine vorherige Lösung, die schön ist.

Source Code

Und hier einige Unit-Tests, die diesen Code (mit MSTest) ausüben:

Test Code

Wenn jemand eine bessere Implementierung hat (und ohne Zweifel eine bessere Umsetzung vorhanden ist), ich Ich freue mich, deine Gedanken zu lesen! Vielen Dank.