Serge Toarca http://www.debuggex.com/blog/ debuggex@toarca.com Debuggex Blog tag:www.debuggex.com/blog,2011-06-11:/atom/ http://www.debuggex.com/blog/favicon.ico http://www.debuggex.com/blog/feed-logo.png 2013-10-01T13:30:00Z acrylamid A true regex tester tag:www.debuggex.com/blog,2013-10-01:/2013/a-true-regex-tester 2013-10-01T13:30:00Z Serge Toarca http://www.debuggex.com/blog/ debuggex@toarca.com <p>How often have you been bitten by a regex? Here's how the story usually goes.</p> <p>Two months ago, you spent 20 minutes crafting a regex. Today, you realize it has a bug and begin fixing it. Except that it now reminds you more of hieroglyphics:</p> <div class="highlight"><pre><span class="o">&lt;</span><span class="sr">/?\w+((\s+\w+(\s*=\s*(?:&quot;&quot;.*?&quot;&quot;|&#39;.*?&#39;|[^&#39;&quot;&quot;&gt;\s]+))?)+\s*|\s*)/</span><span class="o">?&gt;</span> </pre></div> <p>And there aren't any unit tests, because you were nearing a deadline, and writing <em>good</em> unit tests for regular expressions is more tedious than most unit tests. Now you have to spend another 20 minutes figuring out what the regex does before fixing it. You finally fix it and push it to production, only to realize that there was a case that used to work and it doesn't anymore. Sound familiar?</p> <p>Enter Debuggex unit tests. We tried to make it as effortless as possible to add strong unit tests for your expressions. Here's how they work:</p> <ol> <li> <p>Click "Add a unit test". Enter a string that you are testing a regex against. If you're lazy, you can click 'Suggest' and Debuggex will come up with a test case for you.</p> </li> <li> <p>Hover over the matches in the unit test. If all the matches and subgroups look like what you want to extract, click "This looks right". Otherwise click "This looks wrong".</p> </li> </ol> <p>That's it! Whenever you change your regex, all unit tests will be run to make sure they still pass. For a "right" test, Debuggex will make sure all the matches and subgroups are the same. For a "wrong" test, Debuggex will make sure at least one of the matches or subgroups differs. This keeps your regex backwards-compatible with previous versions, so you don't introduce new bugs as you fix old ones. The unit tests also serve as examples for when you return to your regex and have no idea what it does.</p> <p>Debuggex is a regex tester in the very literal sense. We hope this helps you build a good workflow around working with regular expressions.</p> <p>As always, we love feedback!</p> A composable regex repository tag:www.debuggex.com/blog,2013-09-17:/2013/a-composable-regex-repository 2013-09-17T11:00:00Z Serge Toarca http://www.debuggex.com/blog/ debuggex@toarca.com <p>Debuggex has launched a regex repository! Starting today, this is how you can match an IPv4 address on <a href="http://www.debuggex.com/blog/">our site</a>:</p> <div class="highlight"><pre><span class="p">(</span>?<span class="o">&amp;</span><span class="p">.</span><span class="n">ipv4</span><span class="p">)</span> </pre></div> <p>(The <code>(?&amp;</code> syntax is borrowed from PCRE's <a href="http://www.autoitscript.com/autoit3/pcrepattern.html#SEC23">regex subroutines</a>.)</p> <p>The concept is really simple - Debuggex has a list of pre-built expressions that you can use instead of wasting your time figuring them out by yourself. We've already got a list of almost a hundred expressions, and we are constantly adding more.</p> <p>There are a few key features that make our implementation significantly better than what you may have seen in other places.</p> <h3>Unit Tests</h3> <p>Debuggex was designed from the start with unit-testing and backwards compatibility in mind. Each regex in the repository has a suite of tests that make it bulletproof.</p> <p>The unit tests also serve as <strong>working examples</strong> for how to use a regex. Ultimately, you spend less time fiddling around, and more time focusing on the things that matter to you.</p> <h3>Composability</h3> <p>Regular expressions tend to be at a very low abstraction level. If you want to find something in a log file, you should be thinking in terms of ip addresses and urls - not dots, digits, and slashes. Working at such a low level quickly gets very complicated.</p> <p>Composability makes abstraction way easier. Suppose you have a log file with entries consisting of an IP address (either IPv4 or IPv6) followed by a quoted referrer url. Here's how you would match that:</p> <div class="highlight"><pre><span class="p">((</span>?<span class="o">&amp;</span><span class="p">.</span><span class="n">ipv4</span><span class="p">)</span><span class="o">|</span><span class="p">(</span>?<span class="o">&amp;</span><span class="p">.</span><span class="n">ipv6</span><span class="p">))</span> <span class="p">(</span>?<span class="o">&amp;</span><span class="p">.</span><span class="n">quotStr</span><span class="p">)</span> </pre></div> <p>That's it! <strong>Arbitrarily complex expressions are hidden behind a simple variable name</strong>. You can use these just like any other piece of a regex. To turn this into an expression that your language will understand, just click "Code Snippet". Debuggex will compile the expression and give you:</p> <div class="highlight"><pre><span class="n">var</span> <span class="n">regex</span> <span class="p">=</span> <span class="n">new</span> <span class="n">RegExp</span><span class="p">(</span>&quot;<span class="p">((</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:</span>25<span class="p">[</span>0<span class="o">-</span>5<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>2<span class="p">[</span>0<span class="o">-</span>4<span class="p">][</span>0<span class="o">-</span>9<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>1<span class="p">[</span>0<span class="o">-</span>9<span class="p">]{</span>2<span class="p">,</span>2<span class="p">})</span><span class="o">|</span><span class="p">(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="p">]{</span>1<span class="p">,</span>2<span class="p">}))</span><span class="o">\\</span><span class="p">.){</span>3<span class="p">,</span>3<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:</span>25<span class="p">[</span>0<span class="o">-</span>5<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>2<span class="p">[</span>0<span class="o">-</span>4<span class="p">][</span>0<span class="o">-</span>9<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>1<span class="p">[</span>0<span class="o">-</span>9<span class="p">]{</span>2<span class="p">,</span>2<span class="p">})</span><span class="o">|</span><span class="p">(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="p">]{</span>1<span class="p">,</span>2<span class="p">})))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>7<span class="p">,</span>7<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>6<span class="p">,</span>6<span class="p">}:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>5<span class="p">,</span>5<span class="p">}:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>0<span class="p">,</span>1<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>4<span class="p">,</span>4<span class="p">}:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>0<span class="p">,</span>2<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>3<span class="p">,</span>3<span class="p">}:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>0<span class="p">,</span>3<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>2<span class="p">,</span>2<span class="p">}:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>0<span class="p">,</span>4<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>6<span class="p">,</span>6<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:</span>25<span class="p">[</span>0<span class="o">-</span>5<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>2<span class="p">[</span>0<span class="o">-</span>4<span class="p">][</span>0<span class="o">-</span>9<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>1<span class="p">[</span>0<span class="o">-</span>9<span class="p">]{</span>2<span class="p">,</span>2<span class="p">})</span><span class="o">|</span><span class="p">(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="p">]{</span>1<span class="p">,</span>2<span class="p">}))</span><span class="o">\\</span><span class="p">.){</span>3<span class="p">,</span>3<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:</span>25<span class="p">[</span>0<span class="o">-</span>5<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>2<span class="p">[</span>0<span class="o">-</span>4<span class="p">][</span>0<span class="o">-</span>9<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>1<span class="p">[</span>0<span class="o">-</span>9<span class="p">]{</span>2<span class="p">,</span>2<span class="p">})</span><span class="o">|</span><span class="p">(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="p">]{</span>1<span class="p">,</span>2<span class="p">})))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>0<span class="p">,</span>5<span class="p">}:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:</span>25<span class="p">[</span>0<span class="o">-</span>5<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>2<span class="p">[</span>0<span class="o">-</span>4<span class="p">][</span>0<span class="o">-</span>9<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>1<span class="p">[</span>0<span class="o">-</span>9<span class="p">]{</span>2<span class="p">,</span>2<span class="p">})</span><span class="o">|</span><span class="p">(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="p">]{</span>1<span class="p">,</span>2<span class="p">}))</span><span class="o">\\</span><span class="p">.){</span>3<span class="p">,</span>3<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:</span>25<span class="p">[</span>0<span class="o">-</span>5<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>2<span class="p">[</span>0<span class="o">-</span>4<span class="p">][</span>0<span class="o">-</span>9<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>1<span class="p">[</span>0<span class="o">-</span>9<span class="p">]{</span>2<span class="p">,</span>2<span class="p">})</span><span class="o">|</span><span class="p">(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="p">]{</span>1<span class="p">,</span>2<span class="p">})))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:::(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>0<span class="p">,</span>5<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:</span>25<span class="p">[</span>0<span class="o">-</span>5<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>2<span class="p">[</span>0<span class="o">-</span>4<span class="p">][</span>0<span class="o">-</span>9<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>1<span class="p">[</span>0<span class="o">-</span>9<span class="p">]{</span>2<span class="p">,</span>2<span class="p">})</span><span class="o">|</span><span class="p">(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="p">]{</span>1<span class="p">,</span>2<span class="p">}))</span><span class="o">\\</span><span class="p">.){</span>3<span class="p">,</span>3<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:</span>25<span class="p">[</span>0<span class="o">-</span>5<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>2<span class="p">[</span>0<span class="o">-</span>4<span class="p">][</span>0<span class="o">-</span>9<span class="p">])</span><span class="o">|</span><span class="p">(</span>?<span class="p">:</span>1<span class="p">[</span>0<span class="o">-</span>9<span class="p">]{</span>2<span class="p">,</span>2<span class="p">})</span><span class="o">|</span><span class="p">(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="p">]{</span>1<span class="p">,</span>2<span class="p">})))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">})::(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>0<span class="p">,</span>5<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:::(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>0<span class="p">,</span>6<span class="p">}(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}))</span><span class="o">|</span><span class="p">(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:(</span>?<span class="p">:[</span>0<span class="o">-</span>9<span class="n">A</span><span class="o">-</span><span class="n">Fa</span><span class="o">-</span><span class="n">f</span><span class="p">]){</span>0<span class="p">,</span>4<span class="p">}):){</span>1<span class="p">,</span>7<span class="p">}:))))</span><span class="o">\\</span> <span class="p">(</span>?<span class="p">:</span><span class="o">\</span>&quot;<span class="p">((</span>?<span class="p">:</span><span class="o">\\\\</span><span class="p">.</span><span class="o">|</span><span class="p">[</span>^<span class="o">\</span>&quot;<span class="o">\\\\</span><span class="p">]){</span>0<span class="p">,})</span><span class="o">\</span>&quot;<span class="p">)</span>&quot;<span class="p">,</span> &quot;<span class="n">g</span>&quot;<span class="p">);</span> </pre></div> <p>(<a href="http://www.debuggex.com/r/bu2Dp3xPsBPtB0Eh">live demo</a>)</p> <p>How long would it have taken to come up with that expression yourself? Keep in mind that the IP is ensured to be correctly formatted, and any escaped quotes in the referrer url will be correctly matched.</p> <h3>Conclusion</h3> <p>We think you'll find this repository incredibly useful, and hope it'll save you a ton of time.</p> <p>We love feedback! If you have some, <a href="http://www.twitter.com/debuggex">get in touch</a>.</p> <p>p.s. If you'd like to compose using your own named expressions, that will be launching very soon!</p> Sneak Preview of PCRE Support in Debuggex tag:www.debuggex.com/blog,2013-07-04:/2013/sneak-preview-of-pcre-support-in-debuggex 2013-07-04T14:01:00Z Serge Toarca http://www.debuggex.com/blog/ debuggex@toarca.com <p>I'm happy to announce that, starting on Saturday, Debuggex will have support for PCRE regular expressions!</p> <p><strong>Everybody will have free access</strong> until August 1st (tell your friends!). This will be extended until August 15th for those that login with their Persona account.</p> <p>While I'm putting on the finishing touches, here's a preview:</p> <ul> <li> <p><strong>Lookbehinds</strong> Debuggex shows you a backwards-facing sub-diagram to match your intuition about how a <a href="http://www.autoitscript.com/autoit3/pcrepattern.html#lookbehind">lookbehind</a> works.</p> <p><code>(?&lt;!fire)truck</code> <img src="http://www.debuggex.com/blog/static/img/preview_lookbehind.png" alt="PCRE Lookbehind preview" class="centered"/></p> </li> <li> <p><strong>More Flags</strong> PCRE supports <a href="http://www.autoitscript.com/autoit3/pcrepattern.html#SEC11">more flags</a> than JavaScript, and Debuggex now supports them as well. On top of that, Debuggex makes your life easier by showing you you exactly what your inline flags are acting upon.</p> <p><code>foo(?i)bar(?x)baz #comment</code> <img src="http://www.debuggex.com/blog/static/img/preview_flags.png" alt="PCRE flags preview" class="centered"/></p> </li> <li> <p><strong>Named Groups</strong> Debuggex now supports <a href="http://www.autoitscript.com/autoit3/pcrepattern.html#SEC14">named groups</a>, so your expressions can be more readable.</p> <p><code>(?&lt;haha&gt;a+)</code> <img src="http://www.debuggex.com/blog/static/img/preview_namedgroup.png" alt="PCRE named group preview" class="centered"/></p> </li> <li> <p><strong>Recursion</strong> <a href="http://www.autoitscript.com/autoit3/pcrepattern.html#SEC21">Recursion</a> allows your regex to match any context-free grammar. With Debuggex, you can dive down through the recursion to see exactly what's going on. Here's an example that matches properly balanced parentheses.</p> <p><code>^((?:\((?1)?\))+)$</code> <img src="http://www.debuggex.com/blog/static/img/preview_recursion.png" alt="PCRE recursion preview" class="centered"/></p> </li> <li> <p><strong>Atomic Groups</strong> <a href="http://www.autoitscript.com/autoit3/pcrepattern.html#SEC16">Atomic groups</a> are used to improve the performance of your regex with certain engines. Debuggex gives you an indication that part of your expression is atomic.</p> <p><code>a*+</code> <img src="http://www.debuggex.com/blog/static/img/preview_atomic.png" alt="PCRE atomic group preview" class="centered"/></p> </li> </ul> <p>There's a bunch more PCRE features in this release, as well as several JavaScript bugfixes. The renderer has been rewritten, so you should have a much more consistent experience across different expressions.</p> <p>On Saturday, there'll be announcements on Hacker News and Reddit. If you're feeling generous, <em>upvotes will be greatly appreciated</em> :)</p> How my crowdfunding turned into singlefunding tag:www.debuggex.com/blog,2013-06-15:/2013/how-my-crowdfunding-turned-into-singlefunding 2013-06-15T17:58:00Z Serge Toarca http://www.debuggex.com/blog/ debuggex@toarca.com <p>The <a href="http://www.igg.me/at/debuggex"><s>crowdfunding</s> market validation campaign</a> for <a href="http://www.debuggex.com/blog/">Debuggex</a> (a visual regex tester) ended 4 days ago. I had the very specific goal of getting <a href="http://www.debuggex.com/blog/blog/2013/ab-using-crowdfunding-to-validate-your-market/">20 paying customers in 20 days</a>. Unfortunately, I didn't succeed. However, I did reach my funding goal of $960. Debuggex received a total of $4374 in preorders, almost all of it from a single customer.</p> <p>To provide some context, the campaign launched 4 weeks ago and was heavily aimed at single user subscriptions. There were basic ($48) and pro ($140) tiers with varying levels of features, and a cheaper perk to get a Debuggex themed poster ($25) for those that wanted to support the product but weren't willing to commit to a subscription.</p> <p>In total, the campaign had 16 backers. Four backers purchased the $25 poster. Six backers donated $5. That leaves only 6 legitimate customers, of which nobody purchased the pro tier.</p> <p><em>Aside: Debuggex needs paying users more than it needs paying nonusers. To thank you for your continued support (and risk-taking spirit), all backers of the poster and basic tier will be upgraded to the basic and pro tier, respectively.</em></p> <p><strong>91% of all revenue came from a single enterprise customer</strong>. 95% of all revenue was from customers intending to use Debuggex in a work environment. That goes up to 98% if poster sales are excluded.</p> <p>Despite the small sample size, these numbers are a strong indication for where to aim my sales efforts.</p> <p>Here are a few of the things I did wrong:</p> <ul> <li> <p><strong>20 days was too short of a period</strong>. Most people are used to 30-day funding periods, and for them, seeing a project 25% funded with 14 days left is disheartening. 14 of the 16 backers contributed before day 13 of 20.</p> <p>In fact, prior to starting the campaign, I should've asked potential customers to contribute on the first day in order to exploit the <a href="http://en.wikipedia.org/wiki/Herd_mentality">public-vote-of-confidence effect</a> for the full duration of the campaign.</p> </li> <li> <p><strong>I sent personal emails to only 41 people</strong>. I chose to notify those who had already showed significant interest in purchasing. 14 of them became backers, for a conversion rate of 34%. Incidentally, all 14 learned of the campaign only because of my email.</p> <p>In hindsight, this was a big mistake. I should have gotten the word out even to those that had not previously shown direct interest.</p> </li> <li> <p><strong>I should've gotten more feedback on my video before launching the campaign</strong>. If you can't pay attention to what I'm saying because you are distracted by the quality of the video or audio, then I've failed at communcating.</p> <p>Given how important it is for a startup to communicate with its users, I've invested in equipment and software to make sure that never happens again.</p> <p>Unfortunately, I don't have any data about how effective the content of the video was.</p> </li> <li> <p>During the campaign, there was a link from the Debuggex home page to the campaign page. <strong>The click-through rate of that link was an abysmal 2%</strong>. <a href="http://en.wikipedia.org/wiki/A/B_testing">A/B testing</a> could have improved this significantly.</p> <p><a href="http://www.debuggex.com/blog/static/img/lowctr.png"><img alt="What the link looked like" src="http://www.debuggex.com/blog/static/img/lowctr_small.png"/></a></p> </li> </ul> <p>Debuggex will continue to get better. Based on the outcome of this campaign, there will be a lot more focus on the needs of corporate users. If you're part of a company (or government) that uses regular expressions in mission-critical portions of your code or workflow, I'd love to discuss how Debuggex can help solve your problems.</p> <p>I will also keep exploring sustainable ways of getting Debuggex into the hands of single users.</p> <p>If you'd like to give me <a href="http://www.debuggex.com/blog/2013/how-my-crowdfunding-turned-into-singlefunding/mailto:debuggex@toarca.com">feedback</a> on how to improve any aspect of my communication, I'd love to hear it. Compare <a href="http://www.youtube.com/watch?v=9i_phvq2nXU">attempt 0</a> and <a href="http://www.youtube.com/watch?v=yvUi1LxDZGc">attempt 1</a> (re-edited but not refilmed).</p> <p>p.s. There haven't been any public updates for a while, but I promise that something awesome is in the pipeline, and will be released <em>very</em> soon.</p> Persona is the only way to login tag:www.debuggex.com/blog,2013-05-27:/2013/persona-is-the-only-way-to-login 2013-05-27T20:09:00Z Serge Toarca http://www.debuggex.com/blog/ debuggex@toarca.com <p>A couple of weeks ago, <a href="http://www.debuggex.com/blog/">Debuggex</a> gave you the ability to create an account and save regular expressions to the account.</p> <p>Authentication for your account is provided exclusively through <a href="https://login.persona.org/about">Mozilla Persona</a>, and I'd like to explain why that decision was made.</p> <ol> <li> <p>Debuggex is still a one-man team. Resources are very constrained, and time has to be properly managed. <strong>I want to focus on building a kick-ass platform for your regular expressions</strong>. Mozilla is building a kick-ass identity provider/protocol, and using Persona costs me substantially less effort than rolling out my own.</p> </li> <li> <p>I don't want to manage your password. Countless mistakes have been made with storing and managing passwords. While I probably wouldn't make any <a href="http://thenextweb.com/socialmedia/2012/06/06/bad-day-for-linkedin-6-5-million-hashed-passwords-reportedly-leaked-change-yours-now/">extremely terrible mistakes</a>, the risk that I would is enough to keep me up at night. The team at Mozilla is much better suited to handle this.</p> <p>There is an important corollary. Several (awesome) features are in development that inherently require authentication, so <strong>the barrier to creating an account needs to be as small as possible</strong>. Since I am not managing your password, you can trust that creating an account on Debuggex is very low-risk. You need to trust only your identity provider. </p> </li> <li> <p>Persona gives huge improvements in user privacy versus other identity providers. When you login with Facebook, Google, or even OpenID, you are providing information about when and what websites you're logging into. This information can be used to track what you do on the web.</p> <p>With Persona, the identity provider gives your browser a certificate that proves ownership of your email. Your browser then <strong>allows you to login to a website without talking to the identity provider</strong>. You can read a <a href="http://identity.mozilla.com/post/7899984443/privacy-and-browserid">better description</a> or get into the <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Persona/Protocol_Overview?redirectlocale=en-US&amp;redirectslug=Persona%2FProtocol_Overview">nitty-gritty</a></p> </li> </ol> <p>Using Persona <em>exclusively</em> is a very strong vote of confidence. It is currently the best way to do authentication. Despite Debuggex being small, a public vote of confidence encourages the Persona team to continue building awesome stuff. It also encourages other websites to use Persona, and that makes authentication better for everybody. </p> <p>In addition, exclusivity means I am very sensitive to bugs or other problems. I can point the team to the things that have the highest impact for Debuggex users, so that Persona gets even better. In fact, one of the Persona developers has already made a personal commitment to support Debuggex' needs.</p> <p>If you have any feedback on the login flow for Debuggex, or any thoughts on this article, please don't hesitate to email me.</p> (Ab)using crowdfunding to validate your market tag:www.debuggex.com/blog,2013-05-22:/2013/ab-using-crowdfunding-to-validate-your-market 2013-05-22T10:59:00Z Serge Toarca http://www.debuggex.com/blog/ debuggex@toarca.com <p>Today, I am announcing the launch of a <a href="http://igg.me/at/debuggex">crowdfunding campaign</a> for <a href="http://www.debuggex.com">Debuggex</a>, but there's a twist.</p> <p>While most campaigns are built to raise enough funds to make a project possible, that's not the goal for Debuggex. Instead, <strong>the primary goal is to validate the market</strong>.</p> <p>Debuggex is still in beta. However, for all but the simplest regular expressions, users say it already provides a 3x decrease (against their previously preferred tool) in estimated total lifetime development cost. For longer expressions, users estimated even larger gains.</p> <p>So value is already being created. But this is just the beginning. While Debuggex is a great tool for working with individual regular expressions, that's only part of the problem. There is lots of innovation left in this space.</p> <p>I see Debuggex growing into a platform to manage everything about your regular expressions. It will have built-in unit testing, multiple flavors, and a composable library of common expressions. Most importantly, it will be deeply integrated into your working environment.</p> <p>I want to stress that last point again. Deep integration means <em>never having to look at a raw regular expression</em>. Ultimately, this saves you a ton of development and maintenance, even if you use regexes only a few times per year. You can learn more about the planned features on the <a href="http://igg.me/at/debuggex">funding page</a>.</p> <p>Nevertheless, a product must capture some of the value it's creating in order to be sustainable in the long term. This campaign has a very specific goal: <strong>20 backers in 20 days</strong>. If 20 people value the product enough to pay actual cash for access to future features, I'm confident that I can grow the business. Otherwise, it's back to the drawing board to figure out a different way to monetize.</p> <p>So, why did I choose crowdfunding instead of hacking up a preorder page?</p> <p>First of all, the risk that any individual backer takes is significantly reduced. If the funding goes through, the business model is proven. That's a strong incentive to keep building awesome stuff. If it doesn't go through, then nobody has lost any money. Contrast this to being the first customer to pre-order. The business model has not yet been validated, and if there are no other customers, the founder can walk away to chase other ventures.</p> <p>Secondly, crowdfunding tends to generate more buzz. I think this happens because the format for crowdfunding is geared towards showing off creativity and innovation in the best light. There are lots of visuals and a focus on sharing and collaboration. Potential backers can even see how many other backers there are. Plus, the crowdfunding platform has an indirect interest in generating buzz for you, since it gets a cut of the funding.</p> <p>Finally, I think people are more likely to spend money when they're on a platform which is, at its core, about funding projects and businesses. In addition, since this money comes from future customers rather than from investors, all of the funding results in sustainable expansion of the business. To that end, there are several stretch goals explaining how Debuggex will expand.</p> <p>Help me keep on innovating. If you find value in Debuggex and want to get even more, please consider being a <a href="http://igg.me/at/debuggex">backer</a>. If you don't find value in it, but think others would, please share this article with your friends and coworkers.</p> <p>Discuss on <a href="https://news.ycombinator.com/item?id=5751314">Hacker News</a></p> Why the hell am I building a product with a tiny market? tag:www.debuggex.com/blog,2013-04-27:/2013/why-the-hell-am-i-building-a-product-with-a-tiny-market 2013-04-27T11:02:00Z Serge Toarca http://www.debuggex.com/blog/ debuggex@toarca.com <p>Two months ago, I launched a <a href="http://www.debuggex.com/blog/">regex tester</a>.</p> <p>Why would I ever build a product around helping people with their regular expressions? The market is tiny. There are dozens of free alternatives, and only a small percentage of people I've asked said they would pay for my product.</p> <p>There are a few big advantages to be had competing in a smaller market.</p> <ol> <li> <p><strong>In a smaller market, everything happens on a smaller scale.</strong> Successes and failures are smaller in magnitude and take less time to pan out. Less effort is required to build a competitive product, since the existing ones are not as well-developed. The result is a tighter feedback loop for your learning. Debuggex is my first product, so I want to optimize for learning and profit rather than just profit.</p> <p>To date, I've spent less than a month of full-time effort on Debuggex, and it's already a very competitive product. If it turns out to not make any money, I've only lost a month of effort.</p> <p>Twice, my site went down for a few minutes. It was not an enormous problem - there were less than 10 users on at the time. However, I've learned valuable lessons in automating recovery.</p> <p>At launch, there was a bug in my subscription code. It was a blunder, but I didn't sweat it. I only lost 30 emails, and I've learned to prioritize what gets tested earlier.</p> </li> <li> <p><strong>In a smaller market, you can demonstrate expertise.</strong> When you opt for a smaller market, you have a wider choice for a domain that you're skilled in. Coupled with the small scale, this lets you aim at being the <em>absolute best</em> in the market. You have a chance to wow your users and make them loyal to you, even as you move to new ventures.</p> <p>Debuggex already (while still in beta) blows all of its online competitors out of the water. It was designed to answer the question "Why isn't my regex doing what I intend it to?" I've found that question to be by far the most frustrating and time-consuming issue with developers I've talked to, and competing products just can't give you the answer.</p> <p>The way Debuggex answers this question is by allowing you to walk through an automaton step-by-step. Because it's visual, it taps into your innate spatial sense. It also offers hints as to where something may be wrong. You can inspect any portion of your string or regex and see exactly <em>why</em> and <em>how</em> that portion is (or is not) matching.</p> <p>Fortunately, people have noticed. I've gotten hundreds of tweets, many of them filled with emotion (yes, emotion <em>about regexes</em>!). Several people have also emailed me about partnerships, and a few even wrote articles about it!</p> </li> <li> <p><strong>In a smaller market, you can iterate faster on non-programming skills.</strong> Since the product is small enough that I'm building it alone, I don't just program, I do <em>everything</em>. There is no option to pass work off to somebody else.</p> <p>I wrote this article. I built a tutorial video when I found out users didn't know how to use one of the key features. I respond to every tweet, send every email, and configure everything on the server.</p> <p>Consequently, my thoughts have become more coherent. I can speak more clearly. I know how to avoid audible breathing and swallowing on a microphone (much harder than it seems). I've even made new friends and reconnected with old ones.</p> <p>I am learning to sell, apologize, stroke egos, manage expectations, talk to the media, and build a company.</p> </li> </ol> <p>But it's not just about the intangibles. To date, <a href="http://www.debuggex.com/blog/">Debuggex</a> has 120,000 pageviews. A returning user spends an average of 45 minutes(!) every time they visit, and there have been more than 800 people that have visited at least 8 times. Those 800 people have each spent a whopping 6 hours on the site in just two months! If you are one of those 800 people, it's you that I built Debuggex for. Thanks for giving me the opportunity to create something awesome!</p> <p>What are your thoughts? Should your first product be aimed at a small market?</p> <p>Discuss on <a href="https://news.ycombinator.com/item?id=5618409">Hacker News</a>.</p> <p>If you liked this article, you should follow Debuggex on <a href="http://www.twitter.com/debuggex">Twitter</a> and <a href="http://www.facebook.com/debuggex">Facebook</a>.</p>