Hat jemand ein Beispiel, eine HTML-Zeichenfolge (die von einem winzigen MCE-Editor kommt) zu zerlegen und sie mit C # in N Teile zu zerlegen?
Ich muss die Saite gleichmäßig aufteilen, ohne Wörter zu trennen.
Ich dachte daran, nur den HTML-Code zu teilen und das HtmlAgilityPack zu verwenden, um die defekten Tags zu reparieren. Obwohl ich nicht sicher bin, wie man den Splitpunkt findet, sollte er idealerweise auf dem Text und nicht auf dem HTML basieren.
Hat jemand Ideen, wie das geht?
AKTUALISIEREN
Wie gewünscht, hier ein Beispiel für die Eingabe und die gewünschte Ausgabe.
EINGANG:
<p><strong>Lorem ipsum dolor sit amet, <em>consectetur adipiscing</em></strong> elit.</p>
AUSGABE (Wenn in 3 Spalten aufgeteilt):
Part1: <p><strong>Lorem ipsum dolor</strong></p>
Part2: <p><strong>sit amet, <em>consectetur</em></strong></p>
Part3: <p><strong><em>adipiscing</em></strong> elit.</p>
UPDATE 2:
Ich habe gerade mit Tidy HTML gespielt und das scheint gut zu funktionieren, wenn man kaputte Tags reparieren will. Das kann also eine gute Option sein, wenn ich einen Weg finde, die Split Pints zu finden.
AKTUALISIEREN 3
Mit einer Methode, die dieser Truncate-Zeichenfolge für ganze Wörter in .NET C # ähnelt, habe ich jetzt eine Liste von einfachen Textwörtern erhalten, aus denen sich jeder Teil zusammensetzt. Also, sagen wir Tidy HTML verwenden Ich habe eine gültige XML-Struktur für den HTML-Code, und mit dieser Liste von Wörtern, jeder bekam eine Idee, was wäre jetzt der beste Weg, um es zu teilen?
UPDATE 4
Kann jemand ein Problem mit einem Regex sehen, um die Indizes mit dem HTML in der folgenden Weise zu finden:
Geben Sie in der einfachen Textzeichenfolge "sit amet, consectetur" alle Leerzeichen durch die Regex "(\ s | <(. | \ N) +?>) *" Zurück und suchen Sie diese Zeichenfolge theoretisch mit einer beliebigen Kombination aus Leerzeichen und / oder Stichworte
Ich könnte dann einfach Tidy HTML verwenden, um die kaputten HTML-Tags zu reparieren?
Danke vielmals
Matt
Mann, das ist ein Fluch von mir! Ich kann anscheinend nicht von einem Problem weggehen, ohne dafür unverhältnismäßig viel Zeit aufzuwenden.
Ich habe darüber nachgedacht. Ich dachte über HTML Tidy nach, und vielleicht würde es funktionieren, aber ich hatte Mühe, meinen Kopf darum zu wickeln.
Also habe ich meine eigene Lösung geschrieben.
Ich habe dies anhand Ihrer Eingabe und anhand anderer Eingaben, die ich selbst zusammengestellt habe, getestet. Es scheint ziemlich gut zu funktionieren. Sicherlich gibt es Löcher darin, aber es könnte Ihnen einen Ausgangspunkt geben.
Wie auch immer, mein Ansatz war folgender:
HtmlWord
Klasse unten implementiert. HtmlLine
Klasse unten implementiert. HtmlAgilityPack.HtmlNode
Objekt aus zugänglich zu machen. Diese habe ich in der HtmlHelper
Klasse unten implementiert. Bin ich verrückt nach all dem? Wahrscheinlich ja. Aber weißt du, wenn du es nicht anders kannst, kannst du es versuchen.
So funktioniert es mit Ihrer Beispieleingabe:
var document = new HtmlDocument();
document.LoadHtml("<p><strong>Lorem ipsum dolor sit amet, <em>consectetur adipiscing</em></strong> elit.</p>");
var nodeToSplit = document.DocumentNode.SelectSingleNode("p");
var lines = nodeToSplit.SplitIntoLines(3);
foreach (var line in lines)
Console.WriteLine(line.ToString());
Ausgabe:
<p><strong>Lorem ipsum dolor </strong></p>
<p><strong>sit amet, <em>consectetur </em></strong></p>
<p><strong><em>adipiscing </em></strong>elit. </p>
Und jetzt für den Code:
using System;
using System.Collections.Generic;
using System.Linq;
using HtmlAgilityPack;
public class HtmlWord {
public string Text { get; private set; }
public HtmlNode[] NodeStack { get; private set; }
// convenience property to display list of ancestors cleanly
// (for ease of debugging)
public string NodeList {
get { return string.Join(", ", NodeStack.Select(n => n.Name).ToArray()); }
}
internal HtmlWord(string text, HtmlNode node, HtmlNode top) {
Text = text;
NodeStack = GetNodeStack(node, top);
}
private static HtmlNode[] GetNodeStack(HtmlNode node, HtmlNode top) {
var nodes = new Stack<HtmlNode>();
while (node != null && !node.Equals(top)) {
nodes.Push(node);
node = node.ParentNode;
};
return nodes.ToArray();
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using HtmlAgilityPack;
[Flags()]
public enum NodeChange {
None = 0,
Dropped = 1,
Added = 2
}
public class HtmlLine {
private List<HtmlWord> _words;
public IList<HtmlWord> Words {
get { return _words.AsReadOnly(); }
}
public int WordCount {
get { return _words.Count; }
}
public HtmlLine(IEnumerable<HtmlWord> words) {
_words = new List<HtmlWord>(words);
}
private static NodeChange CompareNodeStacks(HtmlWord x, HtmlWord y, out HtmlNode[] droppedNodes, out HtmlNode[] addedNodes) {
var droppedList = new List<HtmlNode>();
var addedList = new List<HtmlNode>();
// traverse x's NodeStack backwards to see which nodes
// do not include y (and are therefore "finished")
foreach (var node in x.NodeStack.Reverse()) {
if (!Array.Exists(y.NodeStack, n => n.Equals(node)))
droppedList.Add(node);
}
// traverse y's NodeStack forwards to see which nodes
// do not include x (and are therefore "new")
foreach (var node in y.NodeStack) {
if (!Array.Exists(x.NodeStack, n => n.Equals(node)))
addedList.Add(node);
}
droppedNodes = droppedList.ToArray();
addedNodes = addedList.ToArray();
NodeChange change = NodeChange.None;
if (droppedNodes.Length > 0)
change &= NodeChange.Dropped;
if (addedNodes.Length > 0)
change &= NodeChange.Added;
// could maybe use this in some later revision?
// not worth the effort right now...
return change;
}
public override string ToString() {
if (WordCount < 1)
return string.Empty;
var lineBuilder = new StringBuilder();
using (var lineWriter = new StringWriter(lineBuilder))
using (var xmlWriter = new XmlTextWriter(lineWriter)) {
var firstWord = _words[0];
foreach (var node in firstWord.NodeStack) {
xmlWriter.WriteStartElement(node.Name);
foreach (var attr in node.Attributes)
xmlWriter.WriteAttributeString(attr.Name, attr.Value);
}
xmlWriter.WriteString(firstWord.Text + " ");
for (int i = 1; i < WordCount; ++i) {
var previousWord = _words[i - 1];
var word = _words[i];
HtmlNode[] droppedNodes;
HtmlNode[] addedNodes;
CompareNodeStacks(
previousWord,
word,
out droppedNodes,
out addedNodes
);
foreach (var dropped in droppedNodes)
xmlWriter.WriteEndElement();
foreach (var added in addedNodes) {
xmlWriter.WriteStartElement(added.Name);
foreach (var attr in added.Attributes)
xmlWriter.WriteAttributeString(attr.Name, attr.Value);
}
xmlWriter.WriteString(word.Text + " ");
if (i == _words.Count - 1) {
foreach (var node in word.NodeStack)
xmlWriter.WriteEndElement();
}
}
}
return lineBuilder.ToString();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using HtmlAgilityPack;
public static class HtmlHelper {
public static IList<HtmlLine> SplitIntoLines(this HtmlNode node, int wordsPerLine) {
var lines = new List<HtmlLine>();
var words = node.GetWords(node.ParentNode);
for (int i = 0; i < words.Count; i += wordsPerLine) {
lines.Add(new HtmlLine(words.Skip(i).Take(wordsPerLine)));
}
return lines.AsReadOnly();
}
public static IList<HtmlWord> GetWords(this HtmlNode node, HtmlNode top) {
var words = new List<HtmlWord>();
if (node.HasChildNodes) {
foreach (var child in node.ChildNodes)
words.AddRange(child.GetWords(top));
} else {
var textNode = node as HtmlTextNode;
if (textNode != null && !string.IsNullOrEmpty(textNode.Text)) {
string[] singleWords = textNode.Text.Split(
new string[] {" "},
StringSplitOptions.RemoveEmptyEntries
);
words.AddRange(
singleWords
.Select(w => new HtmlWord(w, node.ParentNode, top)
)
);
}
}
return words.AsReadOnly();
}
}
Nur um das zu wiederholen: Das ist eine zusammengewürfelte Lösung; Ich bin sicher, dass es Probleme hat. Ich stelle es nur als Ausgangspunkt für Sie vor - wiederum, wenn Sie das gewünschte Verhalten nicht mit anderen Mitteln erreichen können.
Dieser Vorschlag ist nur ein Hack - hoffentlich gibt es einen besseren Weg.
Im Grunde genommen möchten Sie einen Teil des HTML-formatierten Textes aufnehmen und ihn in kleinere Teile aufteilen, in denen die Schriftart usw. des Originals erhalten bleibt. Ich denke, dass Sie den ursprünglichen HTML-Code in ein RTF-Steuerelement oder ein Word-Objekt laden könnten, teilen Sie ihn dort in Stücke, die die Formatierung beibehalten, und geben Sie die Stücke dann als separates HTML aus.
Es kann auch eine Möglichkeit geben, HtmlAgilityPack so zu verwenden, wenn es eine einfache Möglichkeit bietet, Text mit Formatierungsinformationen aus dem ursprünglichen HTML zu extrahieren.