Ich habe eine sehr kleine Teilmenge von Markdown zusammen mit einem benutzerdefinierten HTML-Code, den ich in React-Komponenten analysieren möchte. Zum Beispiel möchte ich diesen folgenden String drehen:
hello *asdf* *how* _are_ you !doing! today
In das folgende Array:
[ "hello ", <strong>asdf</strong>, " ", <strong>how</strong>, " ", <em>are</em>, " you ", <MyComponent onClick={this.action}>doing</MyComponent>, " today" ]
und geben Sie es dann von einer React-Renderfunktion zurück (React rendert das Array ordnungsgemäß als formatiertes HTML).
Grundsätzlich möchte ich Benutzern die Möglichkeit geben, einen sehr begrenzten Satz von Markdowns zu verwenden, um ihren Text in gestaltete Komponenten umzuwandeln (und in einigen Fällen meine eigenen Komponenten!).
Es ist unklug, gefährlich SetInnerHTML zu verwenden, und ich möchte keine externe Abhängigkeit einbringen, da sie alle sehr schwer sind und ich nur sehr grundlegende Funktionen benötige.
Ich mache gerade so etwas, aber es ist sehr spröde und funktioniert nicht in allen Fällen. Ich habe mich gefragt, ob es einen besseren Weg gibt:
function matchStrong(result, i) {
let match = result[i].match(/(^|[^\\])\*(.*)\*/);
if (match) { result[i] = <strong key={"ms" + i}>{match[2]}</strong>; }
return match;
}
function matchItalics(result, i) {
let match = result[i].match(/(^|[^\\])_(.*)_/); // Ignores \_asdf_ but not _asdf_
if (match) { result[i] = <em key={"mi" + i}>{match[2]}</em>; }
return match;
}
function matchCode(result, i) {
let match = result[i].match(/(^|[^\\])```\n?([\s\S]+)\n?```/);
if (match) { result[i] = <code key={"mc" + i}>{match[2]}</code>; }
return match;
}
// Very brittle and inefficient
export function convertMarkdownToComponents(message) {
let result = message.match(/(\\?([!*_`+-]{1,3})([\s\S]+?)\2)|\s|([^\\!*_`+-]+)/g);
if (result == null) { return message; }
for (let i = 0; i < result.length; i++) {
if (matchCode(result, i)) { continue; }
if (matchStrong(result, i)) { continue; }
if (matchItalics(result, i)) { continue; }
}
return result;
}
Hier ist meine vorherige Frage , die zu dieser geführt hat.
font _italic *and bold* then only italic_ and normal
? Was wäre das erwartete Ergebnis? Oder wird es niemals verschachtelt sein?asdf*
ohne dass er verschwindet)Antworten:
Wie es funktioniert?
Es funktioniert, indem ein String Stück für Stück gelesen wird, was möglicherweise nicht die beste Lösung für wirklich lange Strings ist.
Immer wenn der Parser feststellt, dass ein kritischer Block gelesen wird, d. H.
'*'
ein anderes Markdown-Tag, beginnt er mit dem Parsen von Blöcken dieses Elements, bis der Parser sein schließendes Tag findet.Es funktioniert mit mehrzeiligen Zeichenfolgen, siehe zum Beispiel den Code.
Vorsichtsmaßnahmen
Sie haben nichts angegeben, oder ich hätte Ihre Anforderungen falsch verstehen können, wenn die Notwendigkeit besteht, fett und kursiv gedruckte Tags zu analysieren funktioniert meine aktuelle Lösung in diesem Fall möglicherweise nicht.
Wenn Sie jedoch mit den oben genannten Bedingungen arbeiten müssen, kommentieren Sie einfach hier und ich werde den Code optimieren.
Erstes Update: Optimiert die Behandlung von Markdown-Tags
Tags sind nicht mehr fest codiert, sondern eine Karte, die Sie problemlos erweitern können, um sie Ihren Anforderungen anzupassen.
Die Fehler, die Sie in den Kommentaren erwähnt haben, wurden behoben. Vielen Dank, dass Sie auf diese Probleme hingewiesen haben = p
Zweites Update: Markdown-Tags mit mehreren Längen
Der einfachste Weg, dies zu erreichen: Ersetzen von Zeichen mit mehreren Längen durch einen selten verwendeten Unicode
Obwohl die Methode
parseMarkdown
noch keine Tags mit mehreren Längen unterstützt, können wir diese Tags mit mehreren Längenstring.replace
beim Senden unsererrawMarkdown
Requisite problemlos durch einfache Tags ersetzen .Um ein Beispiel dafür in der Praxis zu sehen, schauen Sie sich das an
ReactDOM.render
, das sich am Ende des Codes befindet.Auch wenn Ihre Anwendung funktioniert Unterstützung mehrerer Sprachen, gibt es ungültige Unicode - Zeichen , dass JavaScript erkennt noch, ex .:
"\uFFFF"
kein gültiges Unicode, wenn ich mich richtig erinnere, aber JS noch in der Lage sein , sie zu vergleichen ("\uFFFF" === "\uFFFF" = true
)Auf den ersten Blick mag es hackig erscheinen, aber je nach Anwendungsfall sehe ich bei Verwendung dieser Route keine größeren Probleme.
Ein anderer Weg, dies zu erreichen
Nun, wir könnten leicht den letzten verfolgen
N
(woN
der Länge des längsten Tags mit mehreren Längen entspricht).Es müssten einige Änderungen am Verhalten der Schleife innerhalb der Methode vorgenommen werden
parseMarkdown
, dh es wird geprüft, ob der aktuelle Block Teil eines Tags mit mehreren Längen ist, wenn er als Tag verwendet wird. Andernfalls``k
müssten wir es in Fällen wie markierennotMultiLength
oder ähnlichem und diesen Teil als Inhalt verschieben.Code
Link zum Code (TypeScript) https://codepen.io/ludanin/pen/GRgNWPv
Link zum Code (Vanille / Babel) https://codepen.io/ludanin/pen/eYmBvXw
quelle
This must be *bold*
mitThis must be *bo_ld*
. Es führt dazu, dass der resultierende HTML-Code fehlerhaft istEs sieht so aus, als ob Sie nach einer kleinen, sehr einfachen Lösung suchen. Nicht "Super-Monster" wie
react-markdown-it
:)Ich möchte Ihnen https://github.com/developit/snarkdown empfehlen, das ziemlich leicht und schön aussieht! Mit nur 1 KB und extrem einfach können Sie es verwenden und erweitern, wenn Sie andere Syntaxfunktionen benötigen.
Liste der unterstützten Tags https://github.com/developit/snarkdown/blob/master/src/index.js#L1
Aktualisieren
Gerade über Reaktionskomponenten bemerkt, habe es am Anfang verpasst. Ich glaube, das ist großartig für Sie. Nehmen Sie die Bibliothek als Beispiel und implementieren Sie Ihre benutzerdefinierten erforderlichen Komponenten, um dies zu erreichen, ohne HTML gefährlich festzulegen. Die Bibliothek ist ziemlich klein und klar. Viel Spass damit! :) :)
quelle
Das Ergebnis:
Regexp-Testergebnis
Erläuterung:
In diesem Abschnitt können Sie Ihre Tags definieren:
[*|!|_]
Sobald eines davon übereinstimmt, wird es als Gruppe erfasst und als "tag_begin" bezeichnet.Und
(?<content>\w+)
erfasst dann den vom Tag umschlossenen Inhalt.Das End-Tag muss mit dem zuvor übereinstimmenden Tag identisch sein.
\k<tag_begin>
Wenn es den Test bestanden hat, erfassen Sie es als Gruppe und geben Sie ihm den Namen "tag_end"(?<tag_end>\k<tag_begin>))
.In der JS haben Sie eine Tabelle wie folgt eingerichtet:
Verwenden Sie diese Tabelle, um die übereinstimmenden Tags zu ersetzen.
Sting.replace hat eine Überladung String.replace (regulärer Ausdruck, Funktion) , die erfasste Gruppen als Parameter verwenden kann. Wir verwenden diese erfassten Elemente, um die Tabelle und die ersetzende Zeichenfolge zu generieren.
[Update]
Ich habe den Code aktualisiert. Ich habe den ersten beibehalten, falls jemand anderes keine Reaktionskomponenten benötigt, und Sie können sehen, dass es kaum einen Unterschied zwischen ihnen gibt.
quelle
console.log
Ausgabe lesen, werden Sie sehen, dass das Array voller Zeichenfolgen ist, nicht der tatsächlichen React-Komponenten: jsfiddle.net/xftswh41Sie können es so machen:
quelle
A working solution purely using Javascript and ReactJs without dangerouslySetInnerHTML.
Ansatz
Zeichenweise Suche nach den Markdown-Elementen. Sobald eines gefunden wird, suchen Sie nach dem Ending-Tag für dasselbe und konvertieren Sie es dann in HTML.
Im Snippet unterstützte Tags
Eingabe und Ausgabe von Snippet:
JsFiddle: https://jsfiddle.net/sunil12738/wg7emcz1/58/
Code:
Detaillierte Erklärung (mit Beispiel):
Angenommen, Zeichenfolge ist
How are *you* doing?
Behalten Sie eine Zuordnung für Symbole zu Tags bei["How are "]
und startet die innere Schleife, bis Sie das nächste * finden.Now next between * and * needs to be bold
Wir konvertieren sie in ein HTML-Element per Text und schieben das Array mit Tag = b direkt in die Karte. Wenn Sie dies tun<Tag>text</Tag>
, reagieren Sie intern in Text konvertieren und in Array verschieben. Jetzt ist Array ["wie geht es", Sie ]. Pause von der inneren SchleifeHow are <b>you</b> doing?
Note: <b>you</b> is html and not text
Hinweis : Eine Verschachtelung ist ebenfalls möglich. Wir müssen die obige Logik in Rekursion aufrufen
Unterstützung für das Hinzufügen neuer Tags
map
Objekt mit dem Schlüssel als Zeichen und dem Wert als entsprechendes Tag einUnterstützt es das Verschachteln? Nein
Unterstützt es alle von OP genannten Anwendungsfälle? Ja
Ich hoffe es hilft.
quelle
asdf
im Grunde, dass sie<pre>asdf</pre>
mit dunklem Hintergrund gerendert werden , oder? Lass es mich wissen und ich werde sehen. Sogar Sie können es jetzt versuchen. Ein einfacher Ansatz ist: Ersetzen Sie in der obigen Lösung das `` `im Text durch ein Sonderzeichen wie ^ oder ~ und ordnen Sie es dem Pre-Tag zu. Dann wird es gut funktionieren. Andere Ansätze erfordern etwas mehr Arbeit<pre>asdf</pre>
. Vielen Dank!pre
Tag-Unterstützung hinzugefügt . Lassen Sie mich wissen, ob es funktioniert