Nasıl çalışır?
Gerçekten uzun dizeler için en iyi çözüm olmayabilir, öbek tarafından yığın bir dize okuyarak çalışır.
Ayrıştırıcı, kritik bir parçanın, yani '*'
veya başka bir etiketleme etiketinin okunduğunu algıladığında , ayrıştırıcı kapanış etiketini bulana kadar bu öğenin yığınlarını ayrıştırmaya başlar.
Çok satırlı dizelerde çalışır, örneğin koda bakın.
Uyarılar
Belirtmediniz veya gereksinimlerinizi yanlış anlayabilirdim, hem kalın hem de italik etiketleri ayrıştırma zorunluluğu varsa , mevcut çözümüm bu durumda çalışmayabilir.
Ancak, yukarıdaki koşullarla çalışmak gerekiyorsa, sadece buraya yorum yapın ve kodu değiştireceğim.
İlk güncelleme: etiketleme etiketlerinin nasıl ele alındığını ayarlar
Etiketler artık kodlanmış değil, bunun yerine ihtiyaçlarınıza göre kolayca genişletebileceğiniz bir harita.
Yorumlarda bahsettiğiniz hatalar düzeltildi, bu sorunları işaret ettiğiniz için teşekkürler = p
İkinci güncelleme: çok uzunluklu etiketleme etiketleri
Bunu başarmanın en kolay yolu: çok uzunluklu karakterleri nadiren kullanılan bir unicode ile değiştirmek
Yöntem parseMarkdown
henüz çok uzunluklu etiketleri desteklemese de, prop'ımızı string.replace
gönderirken bu çok uzunluklu etiketleri kolayca bir basitle değiştirebiliriz rawMarkdown
.
Pratikte bunun bir örneğini görmek için ReactDOM.render
, kodun sonunda bulunan 'a bakın .
Başvurunuz bile yapar çoklu dil desteği, orada JavaScript hala tespit ettiği geçersiz Unicode karakterleri, ex .: vardır "\uFFFF"
(eğer doğru geri çağırmak geçerli bir unicode, değil ama JS hala karşılaştırmak mümkün olacak "\uFFFF" === "\uFFFF" = true
)
İlk başta hack-y gibi görünebilir, ancak kullanım durumunuza bağlı olarak, bu rotayı kullanarak önemli bir sorun görmüyorum.
Bunu başarmanın başka bir yolu
Eh, biz kolayca son izleyebilir N
(burada N
en uzun çoklu uzunlukta etiket uzunluğuna karşılık gelir) parçalar.
İçindeki döngünün yöntemin parseMarkdown
davranış biçiminde bazı ince
ayarlar yapılacaktır, yani, geçerli öbeğin çok uzunluklu bir etiketin parçası olup olmadığını kontrol etmek, etiket olarak kullanılıyorsa; Aksi takdirde, gibi durumlarda ``k
, bunu notMultiLength
veya benzer bir şeyi işaretlememiz ve bu yığını içerik olarak itmemiz gerekir.
kod
// Instead of creating hardcoded variables, we can make the code more extendable
// by storing all the possible tags we'll work with in a Map. Thus, creating
// more tags will not require additional logic in our code.
const tags = new Map(Object.entries({
"*": "strong", // bold
"!": "button", // action
"_": "em", // emphasis
"\uFFFF": "pre", // Just use a very unlikely to happen unicode character,
// We'll replace our multi-length symbols with that one.
}));
// Might be useful if we need to discover the symbol of a tag
const tagSymbols = new Map();
tags.forEach((v, k) => { tagSymbols.set(v, k ); })
const rawMarkdown = `
This must be *bold*,
This also must be *bo_ld*,
this _entire block must be
emphasized even if it's comprised of multiple lines_,
This is an !action! it should be a button,
\`\`\`
beep, boop, this is code
\`\`\`
This is an asterisk\\*
`;
class App extends React.Component {
parseMarkdown(source) {
let currentTag = "";
let currentContent = "";
const parsedMarkdown = [];
// We create this variable to track possible escape characters, eg. "\"
let before = "";
const pushContent = (
content,
tagValue,
props,
) => {
let children = undefined;
// There's the need to parse for empty lines
if (content.indexOf("\n\n") >= 0) {
let before = "";
const contentJSX = [];
let chunk = "";
for (let i = 0; i < content.length; i++) {
if (i !== 0) before = content[i - 1];
chunk += content[i];
if (before === "\n" && content[i] === "\n") {
contentJSX.push(chunk);
contentJSX.push(<br />);
chunk = "";
}
if (chunk !== "" && i === content.length - 1) {
contentJSX.push(chunk);
}
}
children = contentJSX;
} else {
children = [content];
}
parsedMarkdown.push(React.createElement(tagValue, props, children))
};
for (let i = 0; i < source.length; i++) {
const chunk = source[i];
if (i !== 0) {
before = source[i - 1];
}
// Does our current chunk needs to be treated as a escaped char?
const escaped = before === "\\";
// Detect if we need to start/finish parsing our tags
// We are not parsing anything, however, that could change at current
// chunk
if (currentTag === "" && escaped === false) {
// If our tags array has the chunk, this means a markdown tag has
// just been found. We'll change our current state to reflect this.
if (tags.has(chunk)) {
currentTag = tags.get(chunk);
// We have simple content to push
if (currentContent !== "") {
pushContent(currentContent, "span");
}
currentContent = "";
}
} else if (currentTag !== "" && escaped === false) {
// We'll look if we can finish parsing our tag
if (tags.has(chunk)) {
const symbolValue = tags.get(chunk);
// Just because the current chunk is a symbol it doesn't mean we
// can already finish our currentTag.
//
// We'll need to see if the symbol's value corresponds to the
// value of our currentTag. In case it does, we'll finish parsing it.
if (symbolValue === currentTag) {
pushContent(
currentContent,
currentTag,
undefined, // you could pass props here
);
currentTag = "";
currentContent = "";
}
}
}
// Increment our currentContent
//
// Ideally, we don't want our rendered markdown to contain any '\'
// or undesired '*' or '_' or '!'.
//
// Users can still escape '*', '_', '!' by prefixing them with '\'
if (tags.has(chunk) === false || escaped) {
if (chunk !== "\\" || escaped) {
currentContent += chunk;
}
}
// In case an erroneous, i.e. unfinished tag, is present and the we've
// reached the end of our source (rawMarkdown), we want to make sure
// all our currentContent is pushed as a simple string
if (currentContent !== "" && i === source.length - 1) {
pushContent(
currentContent,
"span",
undefined,
);
}
}
return parsedMarkdown;
}
render() {
return (
<div className="App">
<div>{this.parseMarkdown(this.props.rawMarkdown)}</div>
</div>
);
}
}
ReactDOM.render(<App rawMarkdown={rawMarkdown.replace(/```/g, "\uFFFF")} />, document.getElementById('app'));
Kod bağlantısı (TypeScript) https://codepen.io/ludanin/pen/GRgNWPv
Kod bağlantısı (vanilya / babel) https://codepen.io/ludanin/pen/eYmBvXw
font _italic *and bold* then only italic_ and normal
? Beklenen sonuç ne olurdu? Yoksa asla yuvalanmayacak mı?