3

我正在使用以下代码递归解析 css@import语句以将嵌套 css 文件加载到 minifer 中。虽然这与标准@import语句完美配合,但它会错误地添加@import带有媒体查询的语句,而不会在它们周围创建条件。

我需要做的是:

  1. 循环通过我的比赛抓住filename小组捕获
  2. 检查是否存在相应的media
  3. 如果是这样,使用捕获的参数将整个加载的 css 包装在媒体查询中
  4. 如果没有,只需添加文件名捕获内容。

例如

@import url(style.css) screen and (min-width: 768px);

变成

@media screen and (min-width: 767px) {
    /* contents of style.css */
}

我用来捕获语句的正则表达式是这样的:

(?:@import\surl\()(?<filename>[^.]+\.css)(?:\)((?<media>[^;]+);|;))

这是正确捕获。我只是对这些课程了解得不够多,无法Regex全部解决。

比我聪明的人能解决这个问题吗?

我的原始代码。

    /// <summary>
    /// Parses the string for css imports and adds them to the 
    /// file dependency list.
    /// </summary>
    /// <param name="css">
    /// The css to parse for import statements.
    /// </param>
    /// <param name="minify">
    /// Whether or not the local script should be minified.
    /// </param>
    /// <returns>The css file parsed for imports.</returns>
    private string ParseImportsAndCache(string css, bool minify)
    {
        // Check for imports and parse if necessary.
        if (!css.Contains("@import", StringComparison.OrdinalIgnoreCase))
        {
            return css;
        }

        // Recursivly parse the css for imports.
        foreach (Match match in ImportsRegex.Matches(css))
        {
            // Recursivly parse the css for imports.
            GroupCollection groups = match.Groups;

            // Check and add the @import params to the cache dependancy list.
            foreach (var groupName in groups["filename"].Captures)
            {
                // Get the match
                List<string> files = new List<string>();
                Array.ForEach(
                    CSSPaths,
                    cssPath => Array.ForEach(
                        Directory.GetFiles(
                            HttpContext.Current.Server.MapPath(cssPath),
                            groupName.ToString(),
                            SearchOption.AllDirectories),
                        files.Add));

                string file = files.FirstOrDefault();
                string thisCSS = string.Empty;

                // Read the file.
                if (file != null)
                {
                    using (StreamReader reader = new StreamReader(file))
                    {
                        // Recursiveley parse the css.
                        thisCSS = this.ParseImportsAndCache(reader.ReadToEnd(),
                                                            minify);
                    }
                }

                // Replace the regex match with the full qualified css.
                css = css.Replace(match.Value, thisCSS);

                if (minify)
                {
                    this.cacheDependencies
                        .Add(new CacheDependency(files.FirstOrDefault()));
                }
            }
        }

        return css;
    }
4

1 回答 1

0

按照评论中的建议,这是最终的工作代码。

/// <summary>
/// Parses the string for css imports and adds them to the file dependency 
/// list.
/// </summary>
/// <param name="css">
/// The css to parse for import statements.
/// </param>
/// <param name="minify">Whether or not the local script should be minified.
////</param>
/// <returns>The css file parsed for imports.</returns>
private string ParseImportsAndCache(string css, bool minify)
{
    // Check for imports and parse if necessary.
    if (!css.Contains("@import", StringComparison.OrdinalIgnoreCase))
    {
        return css;
    }

    // Recursivly parse the css for imports.
    foreach (Match match in ImportsRegex.Matches(css))
    {
        // Recursivly parse the css for imports.
        GroupCollection groups = match.Groups;
        Capture fileName = groups["filename"].Captures[0];
        CaptureCollection mediaQueries = groups["media"].Captures;
        Capture mediaQuery = null;

        if (mediaQueries.Count > 0)
        {
            mediaQuery = mediaQueries[0];
        }

        // Check and add the @import params to the cache dependancy list.
        // Get the match
        List<string> files = CSSPaths
            .SelectMany(cssPath => Directory.GetFiles(
                HttpContext.Current.Server.MapPath(cssPath),
                Path.GetFileName(fileName.ToString()),
                SearchOption.AllDirectories))
            .ToList();

        string file = files.FirstOrDefault();
        string thisCSS = string.Empty;

        // Read the file.
        if (file != null)
        {
            using (StreamReader reader = new StreamReader(file))
            {
                thisCSS = mediaQuery != null
                    ? string.Format(CultureInfo.InvariantCulture,
                                "@media {0}{{{1}{2}{1}}}",
                                mediaQuery,
                                Environment.NewLine,
                                this.ParseImportsAndCache(
                                this.PreProcessInput(reader.ReadToEnd(), 
                                file),
                                minify))
                    : this.ParseImportsAndCache(this.PreProcessInput(
                                                reader.ReadToEnd(), 
                                                file), 
                                                minify);
            }
        }

        // Replace the regex match with the full qualified css.
        css = css.Replace(match.Value, thisCSS);

        if (minify)
        {
            this.cacheDependencies.Add(new CacheDependency(
                                           files.FirstOrDefault()));
        }
    }

    return css;
}
于 2013-03-18T13:38:58.933 回答