c# - 在 C# : extracting all URLs 中解析 CSS

标签 c# css regex parsing url

我需要从 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 解析器,工作正常。

首先,问题包含两个错误:

  1. url (img) 语法不正确,因为在 CSS 语法中 url( 之间不允许有空格。因此, “img6”、“img7”和“img8”不应作为 URL 返回。

  2. 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/

相关文章:

c# - 从选择 datagridview 行时的日期获取数据日

c# - 将数据库 24 小时制转换为 12 小时制

javascript - CSS - 表格数据不在固定表格标题下

c# - 如何在 C# 中按以...开头的属性选择节点

javascript - 使用 bootstrap 模型传递 Id

php - HTML/CSS : create box color in combobox option

html - 最大高度后页面中心的 flexbox

仅适用于英文和数字字符的 Javascript 正则表达式

javascript - 匹配第 n 个字符之前和之后的组

regex - 是否可以在单个正则表达式中执行所有这些字符串验证?