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) }
我需要获取所有的img * URL,而不是noimg * URL(无效的语法或无效的属性或内部注释).
我试过使用好的旧正则表达式.经过一番试错,我得到了:
private static IEnumerable<string> ParseUrlsRegex (string source) { var reUrls = new Regex(@"(?nx) url \s* \( \s* ( (?! ['""] ) (?<Url> [^\)]+ ) (?<! ['""] ) | (?<Quote> ['""] ) (?<Url> .+? ) \k<Quote> ) \s* \)"); return reUrls.Matches(source) .Cast<Match>() .Select(match => match.Groups["Url"].Value); }
这是一个疯狂的正则表达式,但它仍然不起作用 – 它匹配3个无效URL(即2,3和4).此外,每个人都会说,使用正则表达式来解析复杂的语法是错误的.
我们来试试另一种方法.根据this question,唯一可行的选择是ExCSS(其他可能太简单或过时).有了ExCSS,我得到了:
private static IEnumerable<string> ParseUrlsExCss (string source) { var parser = new StylesheetParser(); parser.Parse(source); return parser.Stylesheet.RuleSets .SelectMany(i => i.Declarations) .SelectMany(i => i.Expression.Terms) .Where(i => i.Type == TermType.Url) .Select(i => i.Value); }
与正则表达式解决方案不同,它不列出无效的URL.但它没有列出一些有效的!也就是说9和10.看起来像是known issue with some CSS syntax,如果没有从头开始重写整个库,就无法修复它. ANTLR重写似乎是abandoned.
问题:如何从CSS文件中提取所有URL? (我需要解析任何CSS文件,不仅仅是上面提供的一个例子,请不要用“noimg”或者假设一行声明.)
注:这不是一个“工具推荐”的问题,因为任何解决方案都将是正常的,无论是一段代码,修复上述解决方案之一,还是其他任何内容;我已经明确定义了我需要的功能.
解决方法
所以对于非RegEx解决方案,我想出了以下几点.请注意,需要更多的工作来使此代码更通用来处理任何CSS文件.为此,我也将使用我的text parsing helper class.
IEnumerable<string> GetUrls(string css) { char[] trimChars = new char[] { '\'','"',' ','\t',}; foreach (var line in css.Split(new string[] { Environment.NewLine },StringSplitOptions.RemoveEmptyEntries)) { // Extract portion within curly braces (this version assumes all on one line) int start = line.IndexOf('{'); int end = line.IndexOf('}',start + 1); if (start < 0 || end < 0) continue; start++; end--; // Remove braces // Get value portion start = line.IndexOf(':',start); if (start < 0) continue; // Extract value and trime whitespace and quotes string content = line.Substring(start + 1,end - start).Trim(trimChars); // Extract URL from url() value if (!content.StartsWith("url",StringComparison.InvariantCultureIgnoreCase)) continue; start = content.IndexOf('('); end = content.IndexOf(')',start + 1); if (start < 0 || end < 0) continue; start++; content = content.Substring(start,end - start).Trim(trimChars); if (!content.StartsWith("noimg",StringComparison.InvariantCultureIgnoreCase)) yield return content; } }
更新:
你似乎在问的似乎超出了一个简单的问题stackoverflow的范围.我不相信你会使用正则表达式获得令人满意的结果.您将需要一些代码来解析您的CSS,并处理所有特殊情况.
由于我写了很多解析代码,并且有一段时间,所以我决定玩这个.我写了一个简单的CSS解析器,并写了一篇关于它的文章.您可以在A Simple CSS Parser阅读文章并下载代码(免费).
我的代码解析一个CSS块,并将信息存储在数据结构中.我的代码分隔并存储每个规则的每个属性/值对.但是,从属性值获取URL还需要更多的工作.您将需要从属性值解析它们.
我最初发布的代码将会让您开始了解如何处理此问题.但是,如果您想要一个真正强大的解决方案,那么将需要一些更复杂的代码.你可能想看看我的代码来解析CSS.我使用该代码中的技术,可以用于轻松处理诸如url(‘img(1)’)的值,例如解析引用的值.
我认为这是一个很好的开始.我也可以为你编写剩余的代码.但那是什么乐趣呢?