Eu tenho um subconjunto muito pequeno do Markdown, juntamente com alguns html personalizados que gostaria de analisar nos componentes do React. Por exemplo, eu gostaria de transformar esta seguinte string:
hello *asdf* *how* _are_ you !doing! today
Na seguinte matriz:
[ "hello ", <strong>asdf</strong>, " ", <strong>how</strong>, " ", <em>are</em>, " you ", <MyComponent onClick={this.action}>doing</MyComponent>, " today" ]
e, em seguida, retorne-o da função React render (React renderizará a matriz corretamente como HTML formatado)
Basicamente, quero dar aos usuários a opção de usar um conjunto muito limitado de Markdown para transformar seu texto em componentes estilizados (e, em alguns casos, meus próprios componentes!)
Não é prudente definir perigosamente o SetInnerHTML, e não quero trazer uma dependência externa, porque todas elas são muito pesadas e preciso apenas de uma funcionalidade básica.
Atualmente, estou fazendo algo assim, mas é muito quebradiço e não funciona em todos os casos. Fiquei me perguntando se havia uma maneira melhor:
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;
}
Aqui está a minha pergunta anterior que levou a esta.
font _italic *and bold* then only italic_ and normal
? Qual seria o resultado esperado? Ou nunca será aninhado?asdf*
sem ele desaparecer)Respostas:
Como funciona?
Ele funciona lendo uma sequência de partes por parte, o que pode não ser a melhor solução para seqüências realmente longas.
Sempre que o analisador detectar que uma parte crítica está sendo lida,
'*'
ou seja, qualquer outra tag de redução, ele começa a analisar partes desse elemento até que o analisador encontre sua marca de fechamento.Funciona em cadeias de linhas múltiplas, veja o código por exemplo.
Ressalvas
Você não especificou, ou eu poderia ter interpretado mal suas necessidades, se houver a necessidade de analisar tags em negrito e itálico , minha solução atual pode não funcionar nesse caso.
Se você precisar, no entanto, trabalhar com as condições acima, basta comentar aqui e eu ajustarei o código.
Primeira atualização: aprimora o tratamento das tags de remarcação
As tags não são mais codificadas, mas são um mapa onde você pode estender facilmente para atender às suas necessidades.
Corrigidos os erros que você mencionou nos comentários, obrigado por apontar esses problemas = p
Segunda atualização: tags de remarcação de vários comprimentos
A maneira mais fácil de conseguir isso: substituindo caracteres de vários comprimentos por um unicode raramente usado
Embora o método
parseMarkdown
ainda não suporte tags de vários comprimentos, podemos facilmente substituí-las por uma simplesstring.replace
ao enviar nossarawMarkdown
suporte.Para ver um exemplo disso na prática, veja o
ReactDOM.render
, localizado no final do código.Mesmo que a sua aplicação não suporte a vários idiomas, há caracteres Unicode inválidos se o JavaScript ainda detecta, ex .:
"\uFFFF"
não é um unicode válido, se bem me lembro, mas JS ainda será capaz de compará-lo ("\uFFFF" === "\uFFFF" = true
)Pode parecer hackeado no começo, mas, dependendo do seu caso de uso, não vejo grandes problemas ao usar esta rota.
Outra maneira de conseguir isso
Bem, poderíamos rastrear facilmente o último
N
(ondeN
pedaços corresponde ao comprimento da tag mais longa).Haveria alguns ajustes a serem feitos na maneira como o loop dentro do método
parseMarkdown
se comporta, ou seja, verificar se o pedaço atual faz parte de uma tag de vários comprimentos, se é usado como tag; caso contrário, em casos como``k
, precisaríamos marcá-lo comonotMultiLength
ou algo semelhante e colocar esse pedaço como conteúdo.Código
Link para o código (TypeScript) https://codepen.io/ludanin/pen/GRgNWPv
Link para o código (vanilla / babel) https://codepen.io/ludanin/pen/eYmBvXw
fonte
This must be *bold*
porThis must be *bo_ld*
. Isso faz com que o HTML resultante a ser mal formadoParece que você está procurando uma pequena solução muito básica. Não "super-monstros" como
react-markdown-it
:)Gostaria de recomendar https://github.com/developit/snarkdown, que parece bem leve e agradável! Apenas 1kb e extremamente simples, você pode usá-lo e estendê-lo se precisar de outros recursos de sintaxe.
Lista de tags suportadas https://github.com/developit/snarkdown/blob/master/src/index.js#L1
Atualizar
Só notei sobre componentes de reação, perdi no começo. Portanto, isso é ótimo para você, acredito que tome a biblioteca como exemplo e implemente os componentes necessários necessários para fazê-lo sem configurar HTML perigosamente. A biblioteca é bem pequena e clara. Divirta-se com isso! :)
fonte
O resultado:
Resultado do teste Regexp
Explicação:
Você pode definir suas tags nesta seção:
[*|!|_]
depois que uma delas corresponder, ela será capturada como um grupo e nomeada como "tag_begin".E depois
(?<content>\w+)
captura o conteúdo envolvido pela tag.A tag final deve ser a mesma que a correspondente anteriormente, então aqui é usada
\k<tag_begin>
e, se passou no teste, capture-a como um grupo e dê um nome "tag_end", é o que(?<tag_end>\k<tag_begin>))
está dizendo.No JS, você configurou uma tabela como esta:
Use esta tabela para substituir as tags correspondentes.
Sting.replace tem uma sobrecarga String.replace (regexp, function) que pode receber grupos capturados como parâmetros, usamos esses itens capturados para procurar na tabela e gerar a sequência de substituição.
[Atualização] Atualizei
o código, mantive o primeiro caso alguém não precise de componentes de reação e você pode ver que há pouca diferença entre eles.
fonte
console.log
saída que você verá a matriz está cheio de cordas, não real Reagir componentes: jsfiddle.net/xftswh41você pode fazer assim:
fonte
A working solution purely using Javascript and ReactJs without dangerouslySetInnerHTML.
Aproximação
Pesquisa de caractere por caractere para os elementos de remarcação. Assim que for encontrada, pesquise a tag final e a converta em html.
Tags suportadas no snippet
Entrada e saída do snippet:
JsFiddle: https://jsfiddle.net/sunil12738/wg7emcz1/58/
Código:
Explicação detalhada (com exemplo):
Suponha que se string é
How are *you* doing?
Manter um mapeamento para símbolos para tags["How are "]
e inicia o loop interno até encontrar o próximo *.Now next between * and * needs to be bold
, nós os convertemos no elemento html pelo texto e enviamos diretamente a matriz onde Tag = b do mapa. Se o fizer<Tag>text</Tag>
, reagir internamente converte em texto e empurra para matriz. Agora, o array é ["como está", você ]. Quebra do loop internoHow are <b>you</b> doing?
Note: <b>you</b> is html and not text
Nota : O aninhamento também é possível. Precisamos chamar a lógica acima na recursão
Para adicionar suporte a novas tags
map
objeto com a chave como caractere e o valor como tag correspondenteSuporta aninhamento? Não
Suporta todos os casos de uso mencionados pelo OP? sim
Espero que ajude.
fonte
asdf
que serão renderizados<pre>asdf</pre>
com fundo escuro, certo? Deixe-me saber isso e eu vou ver. Até você pode tentar agora. Uma abordagem simples é: Na solução acima, substitua o `` `no texto por um caractere especial como ^ ou ~ e mapeie-o para pré-tag. Então vai funcionar bem. Outra abordagem precisa de mais trabalho<pre>asdf</pre>
. Obrigado!pre
Também foram adicionados o suporte à tag. Deixe-me saber se ele funciona