我需要从 CSS 文件中获取所有 URL(url()
表达式)。例如:
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”或假定单行声明。)
注意这不是“工具推荐”问题,因为任何解决方案都可以,无论是一段代码、对上述解决方案之一的修复、一个库还是其他任何东西;并且我已经明确定义了我需要的功能。
最佳答案
终于得到Alba.CsCss ,我从 Mozilla Firefox 移植的 CSS 解析器,工作正常。
首先,问题包含两个错误:
url (img)
语法不正确,因为在 CSS 语法中url
和(
之间不允许有空格。因此, “img6”、“img7”和“img8”不应作为 URL 返回。url
函数 (url('img)
) 中未闭合的引号是严重的语法错误;包括 Firefox 在内的 Web 浏览器似乎无法从中恢复,只是跳过 CSS 文件的其余部分。因此,要求解析器返回“img9”和“img10”是不必要的(但如果删除了这两行有问题的行,则这是必需的)。
对于 CsCss,有两种解决方案。
第一个解决方案是rely just on the tokenizer CssScanner
.
List<string> uris = new CssLoader().GetUris(source).ToList();
这将返回所有“img”URL(上面错误 #1 中提到的除外),但还将包括“noimg3”,因为未检查属性名称。
第二个解决方案是正确解析 CSS 文件。这将最接近地模仿浏览器的行为(包括在未闭合的引号后停止解析)。
var css = new CssLoader().ParseSheet(source, SheetUri, BaseUri);
List<string> uris = css.AllStyleRules
.SelectMany(styleRule => styleRule.Declaration.AllData)
.SelectMany(prop => prop.Value.Unit == CssUnit.List
? prop.Value.List : new[] { prop.Value })
.Where(value => value.Unit == CssUnit.Url)
.Select(value => value.OriginalUri)
.ToList();
如果删除了两行有问题的行,这将返回所有正确的“img”URL。
(LINQ 查询很复杂,因为 CSS3 中的 background-image
属性可以包含 URL 列表。)
关于c# - 在 C# : extracting all URLs 中解析 CSS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18262390/