title: How to parse a small subset of Markdown into React components?
body: <p>I have a very small subset of Markdown along with some custom html that I would like to parse into React components. For example, I would like to turn this following string:</p>
  
  <p><code>hello *asdf* *how* _are_ you !doing! today</code></p>
  
  <p>Into the following array:</p>
  
  <p><code>[ "hello ", &lt;strong&gt;asdf&lt;/strong&gt;, " ", &lt;strong&gt;how&lt;/strong&gt;, " ", &lt;em&gt;are&lt;/em&gt;, " you ", &lt;MyComponent onClick={this.action}&gt;doing&lt;/MyComponent&gt;, " today" ]</code></p>
  
  <p>and then return it from a React render function (React will render the array properly as formatted HTML)</p>
  
  <p>Basically, I want to give users the option to use a very limited set of Markdown to turn their text into styled components (and in some cases my own components!)</p>
  
  <p>It is unwise to dangerouslySetInnerHTML, and I do not want to bring in an external dependency, because they are all very heavy, and I only need very basic functionality.</p>
  
  <p>I'm currently doing something like this, but it is very brittle, and doesn't work for all cases. I was wondering if there were a better way:</p>
  
  <pre><code>function matchStrong(result, i) {
    let match = result[i].match(/(^|[^\\])\*(.*)\*/);
    if (match) { result[i] = &lt;strong key={"ms" + i}&gt;{match[2]}&lt;/strong&gt;; }
    return match;
  }
  
  function matchItalics(result, i) {
    let match = result[i].match(/(^|[^\\])_(.*)_/); // Ignores \_asdf_ but not _asdf_
    if (match) { result[i] = &lt;em key={"mi" + i}&gt;{match[2]}&lt;/em&gt;; }
    return match;
  }
  
  function matchCode(result, i) {
    let match = result[i].match(/(^|[^\\])```\n?([\s\S]+)\n?```/);
    if (match) { result[i] = &lt;code key={"mc" + i}&gt;{match[2]}&lt;/code&gt;; }
    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 &lt; result.length; i++) {
      if (matchCode(result, i)) { continue; }
      if (matchStrong(result, i)) { continue; }
      if (matchItalics(result, i)) { continue; }
    }
  
    return result;
  }
  </code></pre>
  
  <p><a href="https://stackoverflow.com/questions/59201967/how-to-match-bold-markdown-if-it-isnt-preceded-with-a-backslash/59202370">Here is my previous question</a> which led to this one.</p>