title: Parsing CSS in C#: extracting all URLs
body: <p>I need to get all URLs (<code>url()</code> expressions) from CSS files. For example:</p>
  
  <pre class="lang-css prettyprint-override"><code>b { background: url(img0) }
  b { background: url("img1") }
  b { background: url('img2') }
  b { background: url( img3 ) }
  b { background: url( "img4" ) }
  b { background: url( 'img5' ) }
  b { background: url (img6) }
  b { background: url ("img7") }
  b { background: url ('img8') }
  { background: url('noimg0) }
  { background: url(noimg1') }
  /*b { background: url(noimg2) }*/
  b { color: url(noimg3) }
  b { content: 'url(noimg4)' }
  @media screen and (max-width: 1280px) { b { background: url(img9) } }
  b { background: url(img10) }
  </code></pre>
  
  <p>I need to get all <code>img*</code> URLs, but not <code>noimg*</code> URLs (invalid syntax or invalid property or inside comments).</p>
  
  <p>I've tried using good old regular expressions. After some trial and error I got this:</p>
  
  <pre><code>private static IEnumerable&lt;string&gt; ParseUrlsRegex (string source)
  {
      var reUrls = new Regex(@"(?nx)
          url \s* \( \s*
              (
                  (?! ['""] )
                  (?&lt;Url&gt; [^\)]+ )
                  (?&lt;! ['""] )
                  |
                  (?&lt;Quote&gt; ['""] )
                  (?&lt;Url&gt; .+? )
                  \k&lt;Quote&gt;
              )
          \s* \)");
      return reUrls.Matches(source)
          .Cast&lt;Match&gt;()
          .Select(match =&gt; match.Groups["Url"].Value);
  }
  </code></pre>
  
  <p>That's one crazy regex, but it still doesn't work -- it matches 3 invalid URLs (namely, 2, 3 and 4). Furthermore, everyone will say that using regex for parsing complex grammar is <em>wrong</em>.</p>
  
  <p>Let's try another approach. According to <a href="https://stackoverflow.com/questions/512720/is-there-a-css-parser-for-c">this question</a>, the only viable option is <a href="https://github.com/TylerBrinks/ExCSS" rel="nofollow noreferrer">ExCSS</a> (others are either too simple or outdated). With ExCSS I got this:</p>
  
  <pre><code>    private static IEnumerable&lt;string&gt; ParseUrlsExCss (string source)
      {
          var parser = new StylesheetParser();
          parser.Parse(source);
          return parser.Stylesheet.RuleSets
              .SelectMany(i =&gt; i.Declarations)
              .SelectMany(i =&gt; i.Expression.Terms)
              .Where(i =&gt; i.Type == TermType.Url)
              .Select(i =&gt; i.Value);
      }
  </code></pre>
  
  <p>Unlike regex solution, this one doesn't list invalid URLs. But it doesn't list some valid ones! Namely, 9 and 10. Looks like this is <a href="https://github.com/TylerBrinks/ExCSS/issues/11" rel="nofollow noreferrer">known issue with some CSS syntax</a>, and it can't be fixed without rewriting the whole library from scratch. ANTLR rewrite seems to be <a href="https://github.com/TylerBrinks/ExCSS/issues/11#issuecomment-20161254" rel="nofollow noreferrer">abandoned</a>.</p>
  
  <p><strong>Question</strong>: How to extract all URLs from CSS files? (I need to parse <em>any</em> CSS files, not only the one provided as an example above. Please don't heck for "noimg" or assume one-line declarations.)</p>
  
  <p><strong>N.B.</strong> This is not a "tool recommendation" question, as any solution will be fine, be it a piece of code, a fix to one of the above solutions, a library or anything else; and I've clearly defined the function I need.</p>